Reproduce a Lab
Reproduce This Lab is the product moment behind every lab manifest: a way for a human or agent to inherit a lab’s research. It has two paths, both implemented inReproduceSidepeek.tsx, both honest about what they actually do.
Path A — Verify (anonymous, zero-cost)
No account needed. This path never touches Convex:verify_artifacts.py exits nonzero on divergence. A divergence is surfaced, never silently regenerated — the script reports what changed, not a new “verified” hash. This is exactly the Level 2 (artifacts_verified) evidence described in Reproducibility Levels.
Path B — Create my copy (signed-in)
Materializes a brand-new, user-owned lab from another lab’s manifest. Signed-in only; the UI shows a sign-in prompt otherwise. Implemented as the Convex actionreproduceLabFromManifest in convex/functions/reproduce.ts, called directly from the client via useAction — see MCP and API access patterns for what that means for non-web-app callers.
1
Verify the user exists
Looked up by
userId. If not found, the action returns { ok: false, reason: "no-user" } immediately.2
Create the lab record
A new
labs row is created (status: "active", isPublic: false), owned by the calling user. Title becomes "<source title> (reproduction)".3
Record provenance immediately
The
reproducedFrom block is written to the new lab’s Convex row right after creation — even if every later step (repo creation, scaffold write) fails. The lab honestly records where it was supposed to come from regardless of what happens next.4
Create the GitHub repo
Same fallback chain as ordinary lab creation: the user’s own repo-scoped GitHub token if connected (Pro), else the
GITHUB_ACCESS_TOKEN Hubify-Projects org PAT. If neither exists, the action returns { ok: false, reason: "no-github-token", labId, slug } — the lab record is kept (so the user doesn’t lose their spot), and the UI shows an explicit “connect GitHub to finish” state rather than a fake success.5
Bind the repo, then scaffold + write files
The standard lab scaffold is built (
buildScaffoldFiles), plus a reproduction-specific lab.yaml (see below), then written to the new GitHub repo in one batch (writeFileSetToGithub).6
Log the event
A
repo.scaffolded event is appended to the lab’s agentEvents ledger, with reproducedFromSlug and write counts in the payload. Severity is warn if any file failed to write, else info.Slug generation
The new lab’s slug isslugify("<sourceSlug>-repro"). On collision, a random 4-character suffix is appended; on a second collision, a timestamp-derived suffix replaces it.
Result shape
What reproducedFrom records
reproducedFrom is a purely additive, fully optional block on the labs Convex table (convex/schema.ts) — every field is v.optional, and it’s only ever set on labs created through this flow:
The generated
lab.yaml itself always looks like this, regardless of what the source reported:
source.authoritative_repo points at the same ultimate upstream repo the source lab points at — the reproduction traces back to the original science, not to the intermediate sanitized -lab clone repo the user actually cloned from in Path A.
MCP and API access patterns
This is the surface with the fewest integration points in Hubify today. Documenting it accurately means documenting the gaps:- No MCP tool wraps
reproduceLabFromManifest. The MCP server’slab_createtool exists, but it calls a different Convex action (functions/github:createLabWithRepo) — an ordinary new lab, unrelated to any manifest or source lab. There is no MCP tool that reads alab.yaml, and no MCP tool that reproduces one. - No CLI command triggers reproduction. The CLI’s
hubify lab create(interactive prompt) also calls the plainfunctions/labs:createmutation — same gap as the MCP tool above. - No public REST endpoint calls it either.
reproduceLabFromManifestis invoked directly as a Convex action from the browser (useAction(api.functions.reproduce.reproduceLabFromManifest)inReproduceSidepeek.tsx). It is, today, a signed-in, web-app-only surface. lab.yamlitself has no serving surface at all.loadLabManifest/listRegisteredLabsare server-side-only Next.js functions readinglabs-registry/off disk; there is no API route, MCP tool, or CLI command that returns manifest content. Reading a manifest today means cloning or browsing thehubifyrepo directly.
So today, the only way to programmatically see whether a lab was reproduced — and from what — is
GET /api/v1/labs (or a direct Convex query against labs). It is not visible through the MCP server or the CLI.