labloopBLOCK
Agent-driven ML researcher in a secure, reproducible KVM lab: five standalone scientific-state MCP servers within per-user VMs with driver / trusted / hostile zone isolation
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
[](https://github.com/cloudcell/labloop/LICENSE) [](https://discord.com/invite/v9JVtpVuUT)
Part of the GnosisLab project.
A persistent scientific loop for AI agents
Most AI agents can reason, call tools and run code. LabLoop gives them something more durable: a persistent scientific loop in which hypotheses, experiments, evidence, belief updates and research memory survive individual runs and inform what happens next.
science → adaptation → meta-adaptation → science
At the science level, the system forms falsifiable hypotheses, runs recorded experiments and updates beliefs from evidence. At the adaptation level, accumulated outcomes can change which hypotheses, experiments or research strategies are pursued next. At the meta-adaptation level, the process used to make those adaptations can itself be evaluated and improved.
LabLoop's defining claim is that self-improvement happens at the research-process level: the system can improve how it investigates a problem without requiring the underlying model to rewrite or retrain its own weights.
This is deliberately narrower than claiming a recursively self-improving model. LabLoop provides infrastructure for auditable, evidence-driven improvement of the research process, with each cycle grounded in persistent scientific state rather than transient agent context.
As adaptation and meta-adaptation become explicit and measurable, LabLoop can support recursive self-improving research systems: systems that improve not only what they know, but how they decide what to try next and how that improvement process itself changes.
Bring your own model and agent; LabLoop provides the scientific loop, durable state and optional isolated execution environment.
LabLoop gives AI age
f3977c81da15OBSERVED · 2026-10-10Connect
Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.
claude mcp add ml-episteme-mcp --env ML_EPISTEME_INGEST_TOKEN=${ML_EPISTEME_INGEST_TOKEN} -- uvx ml-episteme-mcp{
"mcpServers": {
"ml-episteme-mcp": {
"command": "uvx",
"args": [
"ml-episteme-mcp"
],
"env": {
"ML_EPISTEME_INGEST_TOKEN": "${ML_EPISTEME_INGEST_TOKEN}"
}
}
}
}Exposed tools (46)
42 read · 3 write · 1 destructive. Blast radius: 1 tool can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.
| Tool | Risk | Description |
|---|---|---|
abandon_investigation | read | Abandon an open investigation — recorded, not deleted. |
archive_pending_programmes | read | Archive terminal programmes that are still in the live DB. |
ask | read | nonlocal ask_count |
assert_claim | read | for cid, c in claims.items(): |
assess_programme | read | Assess programme health: progressive vs degenerating (commitment 8). |
best_trials | read | r = results.get(programme_id, []) |
check_invariants | read | Audit the lab |
close_campaign | read | Close an open campaign and freeze its promotion score. |
close_tournament | read | Seal the tournament and compute recursive_gain. |
create_study | write | studies[programme_id] = variables |
describe_blob | read | Describe a content-addressed blob by digest (read-only). |
drop_finding | destructive | Drop a provisional finding — it did not survive scrutiny. |
execute_code | write | # Same shape as the real executor — the completed-evidence |
fast_op | read | A test tool inside the deadline. |
get_archive | read | Get details about an archive, including its programmes. |
get_archived_programme | read | Get an archived programme |
get_campaign | read | Read a campaign with its results and evidence trail. |
get_candidate | read | Read one candidate version (read-only). |
get_candidate_lineage | read | Walk a candidate |
get_claim | read | Read a claim with its full provenance bundle. |
get_claims | read | Batch-read claims — one call, many claims. |
get_evaluation_contract | read | Read one evaluation contract (read-only). |
get_improver | read | Read one improver version with its decisions and policies. |
get_incumbent | read | Derive the incumbent candidate from decisions (read-only). |
get_investigation | read | Read an investigation with its full evidence trail and findings. |
get_next_experiment | read | Get the next experiment configuration from the optimizer role. |
get_proposal | read | Read a proposal with its authoritative classification and |
get_tournament | read | Read a tournament with both arms |
get_trial_status | read | return json.dumps({ |
list_active_programmes | read | List all active research programmes. |
list_archives | read | List all archive files (open and sealed). |
list_claims | read | out = [c for c in claims.values() if type is None or c[ |
list_decisions | write | List meta-decisions, oldest first — the insert-only record. |
list_hypotheses | read | List all hypotheses in a programme with their status. |
list_promotion_decisions | read | List a candidate |
list_search_policies | read | List registered search-policy versions. |
list_trials | read | List all trials in a programme with configs and status. |
param_importance | read | variables = studies.get(programme_id, [ |
read_cell_output | read | return json.dumps({ |
read_resource | read | Read a resource by URI — the lab-wide read surface. |
refresh_roster | read | Reconcile the local roster with upstream Loop-0 candidates. |
relate | read | edge_id = f |
slow_op | read | A test tool that outlives the deadline. |
tell | read | results.setdefault(programme_id, []).append(result) |
verify_archive | read | Verify an archive |
verify_data | read | Verify data provenance by re-computing the hash. |
Trust audit
BLOCKgrade F · trust 51/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | FAIL |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | WARN |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (10 observation(s))
- Network
- declared (15 observation(s))
- Shell
- declared (3 observation(s))
- Dependencies
- pinned
- Secrets in source
- none-found
Findings (25)
${h};`)}}return new Function("ud","uv","renderer","syncData",s.join(`${i}`}else if(e!==At.HIGH&&i.substring(0,15)==="precision highp")return i.replace("precision highp","precision mediump");return i}let bs;function Io(){if(typeof bs=="boolean")return bs;try{bs=new Func`),{size:r,syncFunc:new Function("ud","uv","renderer","syncData","buffer",n.join(`-o -iname 'id_rsa*' -o -iname 'id_ed25519*' -o -iname 'id_dsa*' \
-o -iname 'id_ecdsa*' -o -iname '.env' -o -iname '.env.*' \
if curl -fs -m 2 "http://192.168.122.1:8777/MANIFEST" 2>/dev/null \
echo "==> cache endpoint: http://192.168.122.1:8777 (pid $CACHE_HTTP_PID)"
qga_lab "curl -m3 -sf http://127.0.0.1:38080/health >/dev/null" 2>/dev/null && break
CACHE_URL="${LABLOOP_CACHE_URL:-http://192.168.122.1:8777}"until curl -m3 -sf http://127.0.0.1:38080/health >/dev/null 2>&1 \
endstreamendobj34 0 obj<</BaseEncoding/WinAnsiEncoding/Differences[30/minus/uni00A0]/Type/Encoding>>endobj35 0 obj<</Ascent 851/CapHeight 626/CharSet(/minus/uni00A0/space/exclam/percent/ampersand/pare
drop_finding
.labloop-public-export
importlib.import_module(mod)
rec = importlib.import_module(module)
m = importlib.import_module(f"{mod}.clients.adaptors")mod = importlib.import_module(f"{pkg}._grounded_constants")"/artifacts/../../etc/passwd", headers=AUTH
sys.stdout.write(base64.b64decode(st.get("out-data","")or"").decode("utf-8","replace"))sys.stdout.write(base64.b64decode(st.get("out-data","")or"").decode("utf-8","replace"))sys.stderr.write(base64.b64decode(st.get("err-data","")or"").decode("utf-8","replace"))sys.stdout.write(base64.b64decode(
sys.stderr.write(base64.b64decode(
ml-scientist/docs-pub/r-references/val-grounding/13-airsbench-arxiv2602.06855.pdf
the state DBs, never read `ingest.env`. `sudo -u mcp` resolves
Gates applied: no_behavioural_pass.
f3977c81da15full audit observations/trust-audit/mcp-server/cloudcell__labloop.json · Report an issue / request a re-scanAudit history
Every audit this server has had. A grade with a past is a grade somebody is still checking.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-10 | f3977c81da15 | BLOCK | F | 51 | first audit |
Questions
What is the labloop MCP server?
Agent-driven ML researcher in a secure, reproducible KVM lab: five standalone scientific-state MCP servers within per-user VMs with driver / trusted / hostile zone isolation
What tools does labloop expose?
46 in total: 42 read-only, 3 that write, and 1 that can delete or overwrite (drop_finding). Every one is listed on this page with its risk.
Is labloop safe to connect to an agent?
No — not without reading the findings first. The audit graded it F (51/100) and found 5 critical or high issues in the source. Each one is listed on this page with the file and line it is on. Separately from the audit: 1 of its tools can destroy data, so scope the token you give it to what you actually need.
What credentials does labloop need?
It reads ML_EPISTEME_INGEST_TOKEN from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.
How does labloop run?
It speaks streamable-http, so it runs as a service you connect to over the network. It is published on PyPI as ml-episteme-mcp.
How current is this page?
The grade is for one exact copy of the source (f3977c81da15), read on 2026-10-10. The repository is watched and re-audited when it changes.