This handbook takes you from your first Python or Colab result to a page your team can inspect, trace to code and reuse in reports. Python examples target the
luna_repro SDK 0.3.0 and the luna.repro.page.v1 result contract.Online handbook · See a complete example · Connect results · Reproducibility results · Manage my connections
1. What does this feature do?
Run your research code where you already work: Colab, your computer or an independent server. Select the numbers, tables, images and explanations you want to send to LUNA. LUNA arranges them into sections, gives the result page its own address and preserves result versions. You can combine sections from several results in the same lab into a report.
For example, after inference produces
metrics, comparison_df and figure, add a final registration cell to collect the evaluation, comparison table and visual result on one page. Include links to the actual computation so colleagues can inspect the code or notebook. Uploading the model, source dataset or entire notebook is unnecessary.Registration does not run training, inference, a GPU or independent verification. Opening an execution link does not automatically run its code. Researchers prepare the external environment, accounts, data, models, dependencies and execution instructions. Successful registration and scientific success are separate claims.
For your first attempt, follow this sequence.
1. Inspect the complete browser example and its sections.
2. Create the installation-free synthetic example in your project.
3. Install the SDK and run the offline walkthrough.
4. Use Copy connection cell in Connect results and approve in the browser. Finish with
repro.select() to choose the synthetic outputs you need.5. Select sections and save a combined report.
6. Start applying the same pattern to one small result from your research code.
2. Names, identities and permissions
| Name | Meaning | Example |
|---|---|---|
| Project UUID | Identifies the destination project; it is not a secret key | UUID shown in Connect results |
| Connection key | A secret scoped to its issuer and one project | Enter through the hidden prompt |
| Result page | A collection of explanations, metrics, tables and images | Results of one inference run |
| Section | Unit for links and report selection | quality, render |
| Block | An individual item inside a section | Text, metrics, table or image |
| Result version | Immutable snapshot of submitted content | v1, v2 |
| run_id | Execution identity supplied by the producer | A new UUID for a new execution |
| request_id | Identity used to recognize transmission retries | Managed by the SDK |
| Combined report | A report composed from pinned result sections | Evaluation and figures from two experiments |
| outbox | Local directory preserving selected results for transmission | .luna-repro/outbox |
New results start private. Copying a link does not automatically make it readable by someone else. Readers use their own login and current project/material permissions. Do not distribute the author's connection key to teammates. The feature is available only to accounts and projects enabled under the platform's current access policy.
Reuse one connection key for multiple results in the same project; you do not need a new key for each report. Another project requires a key scoped to that project. Project-management permission does not permit viewing someone else's keys.
3. Inspect a complete example before installing
1. Open See a complete example. The displayed data is synthetic teaching data.
2. Inspect how metrics, charts, tables and explanations appear.
3. In Connect results, choose your project and select Choose.
4. Select Try a synthetic example. This explicit action creates two private result pages in the selected project. No connection key or SDK installation is needed.
5. Open the baseline and smoothed links in the completion message.
6. Use Select result on the sections you want, then continue to report composition through the selection bar.
This browser example compares a noisy signal with a moving average. It uses 120 samples and seed 20261011. Baseline RMSE is approximately 0.26832629 and smoothed RMSE is approximately 0.11535325. These are actual synthetic CPU calculations, not Pasa or Teeth3DS+ research performance. Repeating the action with the same account and project reuses the existing examples.
The walkthrough below uses a different synthetic calculation. It corrects an offset across six values, changing MAE/RMSE from 0.5 to approximately 0.1. Do not compare the numbers from these two teaching examples as if they came from the same experiment.
4. Prepare your project and connection key
Connect once from the environment running your research, then reuse that connection for results in the same project. Browser approval is the default; you do not need to paste a key into notebook source.
1. Open Reports → Reproducibility results → Connect results and select your project.
2. Select Copy connection cell and paste it into your notebook's first cell or near the start of your Python file. It prepares the hash-pinned SDK and starts browser approval for the selected project. Use the folded installation instructions if you manage installation yourself.
3. If the SDK is already installed, the following also connects it. Replace the project UUID with the selected project's value.
import luna_repro as repro
repro.connect("YOUR-PROJECT-UUID", label="My Colab")4. Open the approval URL in a browser. Check the signed-in account, project and confirmation code before approving. In Colab or a remote server, open the printed URL yourself if no browser tab opens automatically.
5. The waiting Python process receives approval and connects. Connecting does not publish results. The connection key stays in current-process memory and is not printed into notebook output. A valid connection in that process is reused.
Connect again after restarting the runtime or Python process. Expiration, revocation and loss of project access still apply. An approval timeout is not a successful connection; publication also needs its own successful receipt. Do not approve an unfamiliar program or a request whose code does not match.
For a noninteractive server without browser approval, retain the existing manual-key workflow. In Manage connections → Create connection key, select a label and expiry, and keep the secret in approved storage when it is shown once. Manual keys default to 30 days, with a 1–90 day choice. Never put keys in notebook source/output, Git, screenshots, reports or shared chat. Use an approved secret manager to supply
LUNA_REPRO_TOKEN or a hidden getpass.getpass() prompt. Existing Page/Section examples continue to work.import getpass
import luna_repro as repro
repro.configure(project="YOUR-PROJECT-UUID",
endpoint="https://lunalab-ai.com",
token=getpass.getpass("LUNA connection key: "))configure() only sets local configuration; it does not approve access, validate permissions or send results. connect() establishes a browser-approved connection, and publish() sends selected results.Manage keys through Settings → Reproducibility connections, Reproducibility results → Manage connections, or Project settings → Connections and research tools → Manage connections. A key belongs to its issuer and one project and can serve multiple results; do not create one per report. Project-management permission does not expose another person's key. Revoking a connection preserves results, reports and revisions. Last use and last publication reflect actual successful operations, not issuance alone.
5. Get the public SDK and practice files
The public SDK repository is lunalab-ai/luna-repro-sdk. Installation needs neither the full platform source nor a GitHub login. Public SDK code and synthetic examples do not make your research results public. The repository includes no connection keys, project materials, research results or datasets. Existing connection keys, result IDs, versions, reports and current permissions continue to apply.
Use the platform-tested SDK 0.3.0 release and the wheel command with its SHA-256 below. Installing the SDK does not run an example or publish a result. Public SDK download needs an internet connection but no LUNA key. Uploading to LUNA separately requires your project's connection key and current permissions.
The easiest starting point is Open Colab example. On your computer or server, open walkthrough.py and select Download raw file. The wheel installs the SDK, not the example files. See the canonical SDK installation and upgrade guide for SDK-specific setup; this handbook continues through platform connections, results, reports and Notion.
Download the English HTML handbook, English Markdown handbook, or bilingual handbook and examples ZIP. Extract the guide ZIP to get
examples/walkthrough.py and examples/walkthrough.ipynb. Read or print HTML offline. These files contain no actual connection key or research data.5.1 The existing ZIP installation still works
The Python SDK ZIP remains available through its existing signed-in route. Environments using local installers can download it and run
python -m pip install ./luna-repro-sdk.zip. In Colab, upload the ZIP through the Files panel, then run %pip install /content/luna-repro-sdk.zip. The public wheel is the default path because it needs no ZIP upload.The SDK ZIP extracts into
luna-repro-sdk/, containing the installer and examples/walkthrough.py, walkthrough.ipynb, toy.py, last_cell.ipynb, incremental.ipynb and pasa_adapter.py. The guide ZIP uses examples/; the SDK ZIP uses luna-repro-sdk/examples/. Adjust commands to your actual extraction directory. The computer walkthrough below uses the guide ZIP's examples/ path.6. Follow the walkthrough in Colab
Start with the new quickstart notebook and section 29 for the simpler workflow. Defaults calculate synthetic CPU values, retain a failed-check example and save a local preview. Replace the practice UUID and explicitly choose
CONNECT=True to start browser approval; PUBLISH=True is a separate send choice. Set SHOW_SELECTOR=True for notebook checkboxes. The existing walkthrough below compares two results and retains manual-key input as a compatible exercise.6.1 Install
1. Open the SDK 0.3.0 Colab example. Save a copy in your Drive if needed; never save a key in that copy.
2. Run the first installation cell. It skips installation when SDK 0.3.0 is present; otherwise it installs the pinned wheel over the internet. If another version was already imported, it asks you to restart the runtime. No installer ZIP upload is needed. To install manually or use your existing research notebook, run this command in a new code cell.
%pip install --disable-pip-version-check --no-deps "https://github.com/lunalab-ai/luna-repro-sdk/releases/download/v0.3.0/luna_repro-0.3.0-py3-none-any.whl#sha256=4fc3b6a0ff1d78dbb2ace0ea08dcedc3794e14f3930d0c60f29c42fbb04e2489"3. Check the installation in the same runtime. It should print
0.3.0.import luna_repro
print(luna_repro.__version__)4. If it prints another version, preserve your files and outbox first, restart the runtime, then repeat installation and verification. An already imported module may remain in memory after installation changes.
5. Run the notebook from top to bottom. Defaults are
PUBLISH = False and RETRY = False, so it computes and saves locally only. Installation uses the internet; this synthetic example uses CPU and needs no GPU selection.6.2 Check the result
Expect baseline MAE/RMSE 0.5, corrected approximately 0.1, and samples 6. A value such as
0.09999999999999998 is normal floating-point representation in this example. Output includes Saved: and paths such as .luna-repro/walkthrough-notebook/.../baseline.json and corrected.json. Each run gets a new subdirectory, preserving earlier saved files.6.3 Send to the real platform
1. Replace
PROJECT_ID in the setup cell with your actual project UUID from Connect results. Do not publish with the offline example UUID.2. Rerun setup, calculation and save cells to create Page objects for that project.
3. Change
PUBLISH = False to True in the optional publication cell, and run that cell.4. Enter the connection key in the hidden prompt. It should not be echoed into output.
5. Check for
Published:, a URL and a revision. Pending: is not publication success.6. Open each URL and inspect its metrics, chart, six-row table and interpretation.
7. Return to
PUBLISH = False after practice so a future Run all does not send unintentionally.Colab's
/content files and environment variables may disappear when the runtime restarts or ends. First preserve needed JSON and outbox files in an authorized private location; keep keys separate. Colab's localhost is not your computer's server: use the real LUNA HTTPS origin. Free Colab resources, availability and GPU access are not guaranteed.7. Follow the walkthrough on your computer or server
Use Python 3.10 or later. If you already have a research environment, activate it and install into that same Python with one command. Adding a registration cell to existing research code does not require a new project or environment.
python -m pip install --disable-pip-version-check --no-deps "https://github.com/lunalab-ai/luna-repro-sdk/releases/download/v0.3.0/luna_repro-0.3.0-py3-none-any.whl#sha256=4fc3b6a0ff1d78dbb2ace0ea08dcedc3794e14f3930d0c60f29c42fbb04e2489"python -c "import luna_repro; print(luna_repro.__version__)"The expected version is
0.3.0. Check that python refers to your research environment before installing into a system interpreter. Windows also uses python -m pip in an activated environment. For a fresh start, follow the optional environment step below.7.1 Only when starting fresh: a project virtual environment
In a new practice folder, Windows PowerShell:
py -m venv .venv
.\.venv\Scripts\Activate.ps1Linux/macOS shell:
python3 -m venv .venv
source .venv/bin/activateThen run the installation command above. If PowerShell blocks activation, replace
python in installation and execution commands with .\.venv\Scripts\python.exe; changing execution policy is unnecessary. Linux can similarly use .venv/bin/python directly.7.2 Run the synthetic walkthrough
After extracting the guide ZIP into your current directory:
python ./examples/walkthrough.pyIf you downloaded just the Python file, use
python ./walkthrough.py. For the SDK ZIP, use python ./luna-repro-sdk/examples/walkthrough.py. The default execution makes no network request and saves two JSON files under .luna-repro/walkthrough/NEW-RUN-DIRECTORY/. Check baseline MAE/RMSE 0.5 and corrected approximately 0.1.7.3 Publish to the platform
Publishing occurs only when you provide the endpoint, actual project UUID, and
--publish. Replace YOUR-PROJECT-UUID below with the value from Connect results. Never put a connection key in command arguments.$env:LUNA_REPRO_ENDPOINT = "https://lunalab-ai.com"
python ./examples/walkthrough.py --project "YOUR-PROJECT-UUID" --publishexport LUNA_REPRO_ENDPOINT="https://lunalab-ai.com"
python ./examples/walkthrough.py --project "YOUR-PROJECT-UUID" --publishIf no token environment variable is set, the script prompts with hidden input. Noninteractive servers should use their approved secret-management system. Check both exit code 0 and
Published output. If a result remains pending, the CLI returns 1 and preserves the outbox.7.4 SDK, platform and result versions; upgrade and rollback
| Version | This guide's baseline | Meaning |
|---|---|---|
| SDK | 0.3.0 | Client code installed into your Python environment |
| Result data contract | luna.repro.page.v1 | Result format exchanged by SDK and platform |
| Platform | Deployment version in About | Web/API release, managed independently of the SDK |
Result labels such as
v1 and v2 are separate saved content versions. Installing or changing the SDK does not erase or automatically update existing results, keys or reports.The commands above do not automatically follow new SDK releases. Before changing versions, record
luna_repro.__version__ and keep the wheel URL/SHA-256 or previous ZIP you installed. Test synthetic examples in a new environment before using the hash-pinned command for a tested new release. Avoid installing directly from main or omitting the version during upgrades.To return to this guide's 0.3.0 after trying another version, preserve result JSON/outbox files and reinstall in the same environment with the following command. Preserve files before restarting a running Python process or notebook kernel.
python -m pip install --force-reinstall --disable-pip-version-check --no-deps "https://github.com/lunalab-ai/luna-repro-sdk/releases/download/v0.3.0/luna_repro-0.3.0-py3-none-any.whl#sha256=4fc3b6a0ff1d78dbb2ace0ea08dcedc3794e14f3930d0c60f29c42fbb04e2489"For an earlier version, use its actually retained wheel/SHA-256 or ZIP and check whether it supports your code-provenance features. Rolling back the SDK does not roll back the server database or saved results. You need not delete local results or issue a replacement key.
Starting with the public SDK and synthetic CPU examples requires no separate paid execution service such as Hugging Face, GitHub Actions or RunPod. Your server, networking, storage, chosen Colab resources and AI analysis have separate costs.
8. The smallest complete Python example
After installing the SDK, run this cell unchanged. It needs no external file, pandas or matplotlib and uses an example UUID for offline saving only.
from pathlib import Path
import math
import luna_repro as repro
project_id = "12345678-1234-5678-1234-567812345678" # Offline practice only
reference = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0]
prediction = [value + 0.5 for value in reference]
errors = [actual - expected for actual, expected in zip(prediction, reference)]
metrics = {
"MAE": sum(abs(error) for error in errors) / len(errors),
"RMSE": math.sqrt(sum(error ** 2 for error in errors) / len(errors)),
"samples": len(reference),
}
rows = [[i, target, actual] for i, (target, actual)
in enumerate(zip(reference, prediction))]
page = repro.page(
project_id,
"My first synthetic result",
description="Practice result registration using six synthetic values.",
metadata={"tags": ["synthetic", "practice"]},
evidence={"origin": "synthetic", "execution_status": "completed",
"evaluation_status": "completed"},
)
page.section("conditions", "Conditions").text("Added 0.5 to each reference value.")
page.section("quality", "Quantitative results").metrics(metrics).table(
["index", "reference", "prediction"], rows
)
output = Path(".luna-repro") / ("practice-" + page.page_id + ".json")
page.save(output)
print(metrics) # MAE=0.5, RMSE=0.5, samples=6
print("Saved locally:", output)To publish, replace
project_id with your actual UUID and rerun page construction. The next connection cell sends to the platform when you explicitly execute it.if page.project_id == "12345678-1234-5678-1234-567812345678":
raise ValueError('Rebuild the Page using your real project UUID first.')
repro.connect(page.project_id, endpoint="https://lunalab-ai.com")
receipt = repro.publish(page)
if receipt["status"] == "published":
print("Published:", receipt["url"], "revision:", receipt["revision"])
else:
print("Pending:", receipt["code"], receipt["message"])
print("Preserved:", receipt.get("outbox_path"))9. Add a final cell to your existing research code
Run your existing computation, then select its outputs in a final cell. After connecting the project with
repro.connect(), start with:import luna_repro as repro
selection = repro.select()Choose the outputs you need and inspect the full preview of metrics, tables, images, descriptions and provenance. Recommendations and preview are local steps, not automatic publication. They do not upload all globals or a source-data folder. Being listed as a candidate does not publish research material. See section 29 for selection syntax and
.py differences.If you already know which outputs to send, use an explicit one-line publication. Here
metrics, comparison_df and figure are objects created by your research code; remove variables you do not have. This call really sends results.receipt = repro.publish(metrics, comparison_df, figure, title="My experiment results")
print(receipt["status"], receipt.get("url"))Keep the existing Page/Section API when you want precise section names, descriptions, execution states or computation sources.
page = repro.page(project_id, "My experiment results")
page.section("quality", "Evaluation").metrics(metrics)
page.section("comparison", "Method comparison").table(comparison_df)
page.section("render", "Visual result").figure(figure, "Selected result figure")
receipt = repro.publish(page) # Uses the current connect/configure connectionDefaults do not certify execution or evaluation success. For a genuinely recorded fresh execution, explicitly set Page evidence such as
{"origin": "executed", "execution_status": "completed", "evaluation_status": "not_run"}; change evaluation status only after actually evaluating. Loading historical artifacts remains origin="imported".A final cell cannot recover closed figures, lost variables, unsaved output or the actual computation origin. Convert relevant Tensor values into numbers and select the desired image files. To preserve a matplotlib figure before it closes, opt into a
capture() scope before computation or retain its Figure object/file yourself. Automatic recommendations discover supported objects that remain in the runtime; they do not collect all prior cells or infer exact calculation-cell provenance.10. Accumulate results across cells and preserve intermediate versions
Create a Page once, then add to the same object from later cells. This complete independent example also runs offline.
import luna_repro as repro
project_id = "12345678-1234-5678-1234-567812345678" # Replace before publication
page = repro.page(project_id, "Staged synthetic experiment", evidence={
"origin": "synthetic", "execution_status": "unknown",
"evaluation_status": "not_run",
})
page.section("setup", "Setup").text("Reference [1, 2, 3], prediction [1.2, 1.8, 3.1]")
page.save(".luna-repro/incremental-example-partial.json")
reference = [1.0, 2.0, 3.0]
prediction = [1.2, 1.8, 3.1]
mae = sum(abs(a - b) for a, b in zip(reference, prediction)) / len(reference)
page.section("quality", "Evaluation").metrics({"MAE": mae})
page.evidence.update(execution_status="completed", evaluation_status="completed")
page.save(".luna-repro/incremental-example-complete.json")With a real project and connection configured, call
page.publish() at intermediate and final points to preserve new versions of the same page. A file created only by save() is not a platform version.Reusing a section key appends blocks; it does not replace content. Running
page.section("quality").metrics(...) twice creates two metric blocks. Use a new Page for a new experiment or a new explicit section key. If rerunning cells accidentally duplicates blocks, review the needed data and rebuild from the Page-construction cell. The SDK never silently deletes earlier blocks.To record a new execution under the same page in a new Python session, pass the preserved
page_id and use a new run_id. A new object starts with empty sections; reconstruct everything you want in the new version. Earlier versions remain preserved but are not automatically copied into the object.import uuid
# saved_page_id is the page_id from an earlier successful receipt.
next_run = repro.page(project_id, "Follow-up execution", page_id=saved_page_id,
run_id=str(uuid.uuid4()))
next_run.section("notes", "Scope of this run").text("Results selected for this execution.")11. Block syntax and practical examples
The following snippets are calls made after constructing a Page. Every block method returns the same Section, so you can chain
.text(...).metrics(...).table(...).11.1 Text
page.section("notes", "Explanation", description="Conditions readers need first").text(
"Used six inputs.\nThese values are synthetic."
)Text is plain text, not executable HTML or arbitrary Markdown chart rendering. Line breaks are preserved. Include units, inputs, preprocessing, evaluation scope and failure conditions to make the numbers interpretable.
11.2 Metrics
page.section("quality", "Quantitative evaluation").metrics({
"MAE (mm)": 0.25,
"samples": 24,
"inference_seconds": 1.8,
})Use names that expose units. Values must be finite numbers; strings such as
"0.25", booleans, NaN and Infinity are rejected. In your research code, convert a selected tensor scalar with a suitable expression such as float(value.item()). Do not relabel a partially measured inference duration as whole-pipeline time.11.3 Tables and pandas
page.section("table", "Per-case results").table(
["case", "score", "passed", "comment"],
[["A", 0.25, True, "checked"], ["B", None, False, "not evaluated"]],
)Every row must have the same number of cells as columns. Supported cells are numbers, strings, booleans and None. Do not insert a list, dictionary or tensor object directly into a cell.
pandas is an optional dependency only when your research already uses it.
table(df) does not automatically include the index. Apply this example to an existing df.import pandas as pd # Needed only in research environments using pandas
selected = df[["case", "score"]].copy()
selected = selected.astype(object).where(pd.notna(selected), None)
page.section("comparison", "Comparison table").table(selected)
# Use selected.reset_index() if the index itself is meaningful.Do not turn missing metrics into zero as if they were measured. Preserve None or explain the omission. Screen previews and clipboard copies show only the first 100 rows and 20 columns. Download AI review context to inspect the complete table as JSON.
11.4 PNG and JPEG images
from pathlib import Path
image_path = Path("selected_render.png") # An existing, explicitly selected image
page.section("render", "Front render").image(image_path, "Reconstruction viewed from the front")You can also provide PNG/JPEG bytes from memory.
# image_bytes contains PNG or JPEG bytes produced by your code.
page.section("preview", "Preview").image(image_bytes, "Selected result", name="preview.png")Do not pass a directory, SVG, HTML, PDF, video or 3 D model file to
image(). If an original contains personal or sensitive information, select an appropriately reviewed/redacted image first. The SDK does not anonymize images automatically.11.5 matplotlib figures
import matplotlib.pyplot as plt # Needed only when using matplotlib
fig, ax = plt.subplots()
ax.plot([0, 1, 2], [0.5, 1.5, 2.5], marker="o")
ax.set(xlabel="sample", ylabel="value", title="Synthetic values")
page.section("plot", "Synthetic chart").figure(fig, "Three synthetic values")
plt.close(fig)figure(fig) and its alias chart(fig) export the supplied figure as PNG. After registration into the Page object, closing the figure does not remove the selected image bytes from that object. Interactive Plotly/HTML is not directly supported. Export PNG/JPEG from those tools and explicitly select the file.12. Add precise code, notebook-cell and execution links
Declare provenance using
source. A new section inherits a copy of the Page source unless given a section-specific source. Changing the Page source later does not retroactively change existing sections.The registration call and actual computation can occur at different locations. Without an explicit source, the SDK records the registering filename and line where available. It does not infer notebook cells or Git commits.
This example reads the current commit from an actual Git checkout. Replace the repository URL, relative path and lines with your real computation. Uncommitted changes are not contained in that commit; explain dirty changes separately and preserve any needed source snapshot.
import subprocess
commit = subprocess.check_output(
["git", "rev-parse", "HEAD"], text=True
).strip()
repository_url = "https://github.com/ORG/REPO" # Replace with the real repository
source = {
"repository_url": repository_url,
"commit": commit,
"file": "src/inference.py", # Actual repository-relative computation path
"line_start": 40,
"line_end": 63,
"url": repository_url + "/blob/" + commit + "/src/inference.py#L40-L63",
}
page.section("quality", "Evaluation", source=source)commit cannot contain explanatory placeholders such as main, latest or EXACT-COMMIT-SHA. It accepts an actual 40- or 64-character lowercase hexadecimal commit. If unknown, omit the field and explain the missing evidence. Never substitute a recently inspected repository commit for the code used in a past execution.For a notebook, replace
NOTEBOOK-ID and REAL-CELL-ID with actual values.notebook_url = "https://colab.research.google.com/drive/NOTEBOOK-ID"
page.section("render", "Reconstruction", source={
"file": "experiment.ipynb",
"cell_id": "REAL-CELL-ID",
"url": notebook_url + "#scrollTo=REAL-CELL-ID",
"execution_url": notebook_url,
})Setting
cell_id alone does not produce a clickable cell address. Supply the real cell link in url. Verify the saved notebook's cell ID/link; preserve a separate snapshot hash when its content can change. A human label such as cell 18 is not necessarily the actual cell ID.| source field | Meaning and constraints |
|---|---|
| url | HTTPS link to the actual computation or cell |
| repository_url | HTTPS repository link |
| execution_url | Environment the reader can open; does not execute automatically |
| commit | Actual 40/64-character lowercase hexadecimal commit |
| file | Repository-relative path, / separators; no absolute path or .. |
| line_start, line_end | Integers from 1 through 10,000,000; end cannot precede start |
| cell_id | Actual notebook cell identifier, up to 160 characters |
| snapshot_sha 256 | Actual 64-character SHA256 of the selected source snapshot |
URLs must not contain credentials or query strings. Use a permanent address without sharing-query parameters such as
?usp=.... Use HTTPS on a public hostname; internal IPs, localhost and .local are not supported source URLs. Registering a link never automatically grants access to the external resource.13. Check publication, result versions and metric differences
A successful SDK receipt contains
status, page_id, request_id, revision and url. Only status="published" means accepted intake. The URL is a page address; use the platform's version-specific section link when you need pinned report evidence.1. Open the result URL.
2. Inspect synthetic/imported/executed origin and execution/evaluation status.
3. Check metric units, table rows, image captions and code/execution provenance.
4. In Versions and sharing, choose a result version.
5. If the page has another version, choose a comparison version and select View.
Metric comparison subtracts the comparison value from the current value for matching section keys and metric names. Some metrics improve when lower, others when higher; the interface does not declare a difference an improvement. A researcher must check inputs, data splits, units, alignment and evaluation scope.
Retrying the same saved request does not create a duplicate version. A new Page or newly constructed request may create a new page/version. For recovery, prefer
sync over editing identity fields in saved JSON.14. Build one report from several results
1. Open your first result from Reports → Reproducibility results.
2. Select the sections you need with Select result. Check that each becomes Selected.
3. Open another result page and select additional sections.
4. Review the selection bar and continue to report composition.
5. Enter the report title and explanation/interpretation. Distinguish source facts from your analysis.
6. Reorder items with the up/down controls and remove unwanted items with Remove from selection.
7. Expand Result preview and check the original page, project, version and section.
8. Select Save platform report. The draft starts private to its author.
One report may combine results from multiple projects in the same lab, up to 40 sections. Current access to every referenced original is checked continuously. Sharing a report does not bypass restrictions on its source results. Before sharing, also review the source visibility required by your readers.
To add results to an existing combined report, choose Select more results while editing, select additional sections and return through Add to this report. Review the preserved title, explanation and order, then save. Selecting sections does not immediately change the saved report.
Reports pin the selected result version. If the original later receives v2, a report containing v1 does not silently switch to v2. Select the new version explicitly and save the report when you intend to update it.
15. Organize visibility and material metadata
On the result detail page, the author can choose Private or Project participants under Versions and sharing → Visibility, then save. Project sharing is not public internet publication and still follows current account/project access checks.
Edit grants, researchers and tags opens the existing material-metadata workflow. Tags, related projects and researcher attribution aid discovery; they do not independently grant access. Results are also discoverable under the Reproducibility material category.
SDK
metadata currently accepts tags only. Adding arbitrary grant/researcher fields is rejected. First-publication tags initialize the material catalog, while later SDK submissions do not silently overwrite catalog tags edited by a person. Producer tags remain preserved in each immutable result manifest.Revoking a key or losing project access does not automatically delete existing result versions. Copies already downloaded or delivered to Notion cannot be recalled solely by revoking LUNA access.
16. Copy/paste and direct Notion delivery
16.1 Copy content
1. Select Copy content and source on a section.
2. Paste into the platform's report editor or the intended Notion location.
3. Check the title, table, explanation and source link formatting.
4. For a link alone, use Share and AI review → Copy link.
HTML/image paste behavior depends on the destination app and browser. Clipboard images reference protected LUNA URLs; that does not mean Notion has permanently stored an image attachment. Table previews/copies are also limited to 100 rows and 20 columns. Use direct delivery when you need the selected image bytes preserved in Notion.
16.2 Add directly to Notion
1. Choose Publish to Notion from the intended result, section or combined report. A publication panel opens on the same screen.
2. Check the grant, project and page name under Notion destination. A unique connection for the same project is selected for you; otherwise select the intended destination. The current result/report supplies the title and a preview is prepared automatically.
3. Review the images, tables, narrative and destination, then select Publish to Notion. The default creates a new child page. Use Publication options to change the title or append to the configured page.
4. Follow progress in the same panel and choose Open in Notion to inspect the actual page. Opening the panel and previewing never publish.
Direct delivery uploads selected image originals and creates native Notion heading, paragraph, table and image blocks. It does not overwrite existing human-authored text. The integration needs content-insertion permission, and the destination page must be shared with it. A delivery supports 40 sections,10 images and 99 rows/40 columns per table; split larger selections. A preview expires after 10 minutes, after which you must review again.
Distinguish queued, sending, confirmed, rejected and uncertain states. If the outcome is uncertain, inspect Notion before resending. Follow Check publication status using the actual page ID you confirmed. Some interruptions, such as an image-only upload interruption, cannot be reconciled through that page check. Manage the visibility of delivered copies separately in Notion.
17. Continue analysis in AI consultation, ChatGPT or Codex
Use Share and AI review → Review with AI on a section, or download AI review context. Download AI review context near the result header provides JSON for a pinned version: metrics, tables, explanations, provenance and status. It does not automatically include image bytes, complete external source or models. Image links remain subject to current platform access.
A useful request is:
First verify this result's pinned version and code provenance.
Identify evaluated inputs, units, omitted conditions and failure records.
Separate conclusions supported by these numbers from unsupported claims.
Inspect the actual accessible code, then propose the next experiment and changes.
Do not start training, GPU execution or external publication yet.In ChatGPT or Codex, deliver the result through available connection tools or an explicit attachment. Check which tools the host actually exposes. A link alone does not transfer private GitHub/Drive permissions or complete source code. Provide the source commit, files/functions and data description needed for analysis within your authorized scope.
Reading/downloading makes no AI call. Actual consultation uses existing account permissions and budgets. Record generated code, synthetic checks, real research execution and independent verification separately. Review AI-proposed changes, validate them in your existing development environment and connect the resulting evidence through a new result page/version.
18. Offline storage, recovery and key rotation
18.1 Saving is separate from sending
page.save("result.json") only writes a file. page.publish() first writes selected content atomically into the outbox, then attempts transmission. Missing endpoint/key or transport failure usually returns pending and a preserved path. Invalid tables, source references or checksums may be rejected before saving.Outbox and JSON files contain selected research content and images. Treat them as private research data and keep them out of Git. The SDK does not store the token/endpoint in result bundles, but it is not a universal detector of every secret that might be selected. Review what you send.
18.2 Retry the same request
After fixing the connection, explicitly run this in the configured Python session.
import luna_repro as repro
outcomes = repro.sync(".luna-repro/outbox")
for receipt in outcomes:
print(receipt["status"], receipt.get("url") or receipt["code"])The walkthrough uses a per-run outbox, so pass the printed
.../NEW-RUN-DIRECTORY/outbox path. In its notebook use repro.sync(run_folder / "outbox"). A wrong directory may return an empty list; check the actual saved location.The CLI also works. It reads the token from the session environment and does not accept it as a command argument.
python -m luna_repro sync --outbox .luna-repro/outbox
python -m luna_repro publish selected-result.jsonsync retries outbox JSON files without successful receipts. publish file.json sends that file directly and returns CLI success/failure; it does not independently create an outbox receipt. There is no infinite retry or automatic waiting. Successful originals and receipts are retained.Use
page.publish(strict=True) when a pipeline must treat transmission failure as an exception. Errors are sanitized to avoid displaying tokens or raw remote response bodies. HTTP redirects are refused; configure the final HTTPS endpoint.18.3 Expired, lost or replaced keys
Issue a new key → update the runtime secret → confirm actual result intake → revoke the old key. You do not need to rebuild saved result JSON for a new key. Distinguish expired, revoked and project-access-unavailable states. You can revoke your own key even after losing project access. Revocation prevents later API use while preserving previously registered results.
19. Apply the adapter to existing Pasa outputs
Separate historical output import from a fresh Colab execution. A page imported by the Pasa adapter verifies SDK registration, not a new run of a modified Colab notebook or independent reproduction. Preserve the original notebook and saved result versions; use a new run ID/output folder and the execution copy's actual cell IDs. Distinguish computation cells, registration cells and reference code. Notebook preparation, synthetic checks, GPU execution and platform publication each require their own evidence. If data/model access or a free GPU has not been confirmed, actual execution remains unverified.
The adapter imports selected files from an existing Pasa output directory; it does not run new inference. It does not automatically download or modify the original notebook, models or data.
1. Run the existing
VGGT_Gaussian_Surfels_Colab.ipynb in your own environment and identify the real output directory.2. Install the SDK and place the downloaded
pasa_adapter.py somewhere importable.3. Set
RUN_DIR to that existing directory. It must contain run_manifest.json.4. Prepare the project UUID and connection.
5. First save local JSON and inspect what was selected.
6. Call
publish() explicitly only when ready.from pasa_adapter import build_page
RUN_DIR = "/content/my-existing-pasa-run" # Replace with the actual output directory
project_id = "12345678-1234-5678-1234-567812345678" # Replace with the real project UUID
page = build_page(RUN_DIR, project=project_id)
page.save(".luna-repro/pasa-selected-result.json")
# Run explicitly after reviewing the connection, project and selected content:
# receipt = page.publish()
# print(receipt["status"], receipt.get("url") or receipt["message"])The adapter selects these files:
| Path | Treatment |
|---|---|
| run_manifest.json | Required; records bounded status/conditions and hashes |
| camera_checks.json | Preserves diagnostic rows and failures if present |
| method/case/renders/003_render.png | Selects this image for method/case entries declared in the manifest |
| evaluation/comparison.csv | Imports the comparison table if present |
It does not upload the complete manifest, raw dataset, checkpoint or source tree. It rejects paths/symlinks escaping the chosen directory. It does not invent missing performance, timing or VRAM observations.
Pass
gt_available=True only when ground truth was actually configured and a valid comparison CSV exists. Otherwise evaluation stays not_run. A completed pipeline is not completed scientific verification. Failed camera diagnostics remain visible even if a later render was generated.Add
notebook_url, repository_url, commit and notebook_sha256 only when actually known. The same project and manifest hash produce the same page/run IDs. A different owner importing identical output into a separate page should explicitly pass a new page_id=str(uuid.uuid4()) and explain its provenance/import scope. A fresh CUDA execution and independent reproduction require separate evidence.20. Complete API reference
For a first use, follow
connect() → select() → preview/send in sections 4, 9 and 29. The Page/Section API below remains available for precise section structure, provenance and execution evidence. See the pinned SDK 0.3.0 usage guide for SDK-specific syntax.20.1 Page
repro.page(project, title, *, description="", endpoint=None, token=None,
page_id=None, run_id=None, metadata=None, evidence=None,
source=None, outbox=None)This is parameter-reference notation. The actual convenience wrapper is
page(project, title, **kwargs) and forwards to Page. project, page_id and run_id are UUIDs; omitted page/run IDs are generated. metadata supports only {"tags": [...]}. You can pass endpoint/token directly, but never hard-code a real key in shared source; use the session environment or hidden input.| Method | Result and behavior |
|---|---|
| section(key, title=None, description="", source=None) | Section; description/source are keyword-only; existing key reuses its append target |
| bundle() | Validated dict copy, including request_id |
| save(path) | Saved Path; no network call |
| publish(endpoint=None, token=None, strict=False, timeout=30) | Keyword-only arguments; published or pending receipt |
20.2 Section
| Method | Input |
|---|---|
| text(text) | Plain text |
| metrics(values) | Dict of names to finite numbers |
| table(columns, rows=None) | Columns and rows, or a pandas-compatible DataFrame |
| image(path_or_bytes, caption="", name=None) | PNG/JPEG file or bytes; name is keyword-only |
| figure(figure, caption="") | Explicit figure exported as PNG, or an image path |
| chart(figure, caption="") | Alias of figure |
20.3 Files and retries
bundle = repro.load_bundle("selected-result.json")
# Returns a dict; it does not reconstruct a Page object.
receipt = repro.publish_bundle(bundle, timeout=30)
outcomes = repro.sync(".luna-repro/outbox", timeout=30)The publication calls above perform real transmission; prepare the files and connection before executing them.
publish_bundle and sync accept endpoint, token and timeout keyword arguments. Omitted connection values come from LUNA_REPRO_ENDPOINT and LUNA_REPRO_TOKEN. PublishError provides code, optional retry_after and a fixed sanitized message.Direct HTTP integrations use
POST /api/repro/v1/pages/, GET /api/repro/v1/pages/{page_id}/ and GET /api/repro/v1/pages/{page_id}/versions/{number}/. These are project-bearer endpoints and reject browser cookies/Origin. Most users should use the SDK. Do not mix the legacy ReproKit event-v1 contract with this result-page schema.21. Size, cost and status limits
| Item | Current SDK/platform limit |
|---|---|
| Python | 3.10 or later |
| Page/section title | SDK 300 characters |
| Page/section description | 12,000 characters |
| Text block | SDK 20,000 characters |
| Section key | 1–80 characters; alphanumeric first, then letters/numbers/underscore/hyphen |
| Metrics block | 1–100 entries;160-character names; finite numbers |
| Table | 1–100 columns,0–2,000 rows;160-character headings;4,000-character string cells |
| PNG/JPEG | 8 MiB each; longest side 8192;16 M total pixels; single frame |
| Entire page | 16 MiB JSON including base 64;100 sections/500 blocks/100 unique images |
| Tags | Up to 30,100 characters each |
| Transmission timeout | Default 30 seconds; greater than 0 and at most 120 |
| Keys | Default 30 days, range 1–90;30 active per user |
| Page versions | Up to 10,000 |
| Default project storage | 1 GiB total normalized result JSON plus original image bytes |
| Default write rate | 120 requests per user/600 per project per 15 minutes |
| Default read rate | 300 requests per user/1,500 per project per 15 minutes |
| Combined report | 40 sections in one lab;1 MiB selected JSON;150,000-character body |
| Notion | 20 sections/10 images;99 rows/40 columns per table;400 KB native JSON |
Storage/rate policies can differ by deployment. The 1 GiB figure is a logical result-storage total, not actual database disk or billed size. Base 64 expands image data, so two 8 MiB images do not necessarily fit into a 16 MiB JSON bundle.
Registration, viewing, report composition and Notion delivery do not themselves start extra AI or GPU work. Server storage/transfer and existing external-service charges are separate. Actual AI consultation and research execution follow their own environment's permissions and budget.
22. Troubleshooting, one issue at a time
| Symptom | What to check or do |
|---|---|
| ModuleNotFoundError: luna_repro | Install in the current kernel/environment; use Colab %pip or the selected Python's -m pip |
| ZIP not found | Upload the ZIP to Colab runtime Files; notebook upload alone does not provide it |
| UUID error | Use the project UUID from Connect results, not its name or secret key |
| Empty project list | Check account, membership and enabled access scope with the administrator |
| Cannot redisplay a key | Expected; use the saved secret or issue a replacement |
| 30 active-key limit | Revoke an unused key you own before issuing another |
| pending / connection_required | Check endpoint, key and timeout format; locate the saved JSON and retry explicitly |
| authorization_required /403 | Check project/key match, key expiry/revocation and current account/project access |
| transport_error | Check final HTTPS endpoint, network and server; do not use a redirecting address |
| 413 or request_limit | Reduce selected images/blocks or split the page |
| storage_quota | Review project storage policy and selected size; do not delete older evidence blindly |
| rate_limited /429 | Wait for retry_after if given, then retry explicitly; do not loop automatically |
| NaN/Infinity rejection | Investigate missing/infinite values; omit invalid metrics with an explanation; tables allow None |
| Table row-length error | Match every row's number of cells to columns |
| SVG/HTML image rejection | Export a bounded PNG/JPEG instead |
| Source commit error | Supply an actual lowercase 40/64-character hash or omit the field |
| Source URL error | Remove query/auth/internal addresses; use a permanent public-host HTTPS URL |
| Cell link opens the wrong place | Verify the real cell ID and sharing scope; cell_id alone creates no link |
| Duplicate metric blocks | Repeated a section-append cell; rebuild the Page or use an explicit new key |
| Same experiment became a new page | Reexecuting Page construction generates new identities; use sync for recovery |
| Empty sync result | Check the outbox path and existing successful receipts |
| request_conflict / page_conflict | Check original request identity, page owner and project; do not randomly rewrite JSON IDs |
| version_limit | Preserve the old page, create a new page and explain/link the relationship |
| Teammate cannot open a link | Check login, current project access and original visibility; do not share a key to bypass access |
| Report save fails | Check section count, same-lab scope, original access, body size and concurrent edits |
| Image does not paste into Notion | Use direct Notion delivery through an authorized connection |
| No Notion destination | Check saved integration, management scope, destination sharing and insertion permission |
| Uncertain Notion result | Inspect the destination and reconcile the remote receipt; do not resend blindly |
| AI cannot inspect code | Provide actual accessible source tools/permissions, commit and file; a result link is not full code |
When asking for help, include the page URL, time, SDK version, error code, expected result and actual result. Do not include connection keys, personal information, private research originals, complete environment variables or authentication headers.
23. Verify that your first practice is complete
1. The offline example produced MAE/RMSE 0.5 and approximately 0.1.
2. Your actual project UUID and own key received a
published receipt.3. You inspected metrics, charts, tables and provenance on both platform pages.
4. You selected sections from different results and saved a report.
5. You checked the visibility of both original results and the report.
6. You can continue review using a section link or downloaded AI context.
7. Next, choose one small table or figure from real research and register it the same way.
This practice teaches result registration and reporting. Scientific reproducibility additionally requires precise code, data, model, environment and evaluation identities, followed by separate execution and review evidence.
24. Preserve calculation lines, cells and selected code with SDK 0.3.0
A filename-only older result contains limited original evidence. Its fixed revision is not rewritten. Use the helpers below when registering new results to include a precise location and optional selected text. Recreating the web synthetic demo adds a new CPU-computed, source-enriched revision to the same canonical example page ID. Previous content, hashes and report references remain intact, and an identical repeated request does not create another revision. Trashed examples are never automatically restored. The public finished example also offers Calculation source → View calculation code, opening the corresponding lines of the actual teaching file.
24.1 What is automatic and what must I select?
The default SDK can record the Python call that registers a result. It does not infer which earlier function or cell calculated it. Virtual notebook execution frames may have no file location. Select computation-related locations explicitly with
source.function(...), source.file(...) or source.notebook(...). The default is snapshot=False, which excludes source text. Only an explicit snapshot=True includes selected code in the bundle. Helpers do not save bundles, publish results or execute the selected code.| Displayed evidence | Meaning |
|---|---|
| Result registration location | The SDK call site; it can differ from the calculation |
| User-selected computation code | A calculation range supplied by the user, not proof of successful execution |
| Function/class or cell definition | A saved definition; whether it was called is separate evidence |
| Reference code · execution identity unconfirmed | A review copy whose identity with an earlier execution is unconfirmed |
| Selected code text and hash preserved | Selected text and SHA256 stored with the fixed result revision |
| Producer observed file/commit match | Selected local file bytes matched a local Git commit. The server did not independently verify GitHub or execution |
| Link assembled · external access/execution unverified | A navigation address was constructed. External login, response and execution were not verified |
24.2 A complete runnable Python-file example
Install SDK 0.3.0, save this code as a new
source_example.py, and run python source_example.py. It uses __file__, so it is a file example rather than a cell to paste unchanged into a notebook. It saves the MAE of three synthetic values (0.5), the calculation function's actual lines and its selected text to local JSON. The UUID is for offline practice. No network, GPU or AI call occurs. Every execution uses a new page ID and preserves previous files.from pathlib import Path
import luna_repro as repro
def calculate():
reference = [0.0, 1.0, 2.0]
prediction = [value + 0.5 for value in reference]
return sum(abs(a - b) for a, b in zip(prediction, reference)) / len(reference)
selected = repro.source.function(
calculate, root=Path(__file__).resolve().parent, snapshot=True,
)
page = repro.page(
"12345678-1234-5678-1234-567812345678", "Source selection practice",
evidence={"origin": "synthetic", "execution_status": "completed",
"evaluation_status": "completed"},
)
page.section("metric", "Computed MAE", source=selected).metrics({"MAE": calculate()})
saved = page.save(Path(".luna-repro") / (page.page_id + ".json"))
print("Saved locally:", saved)
print("Source:", selected["file"], selected["line_start"], selected["line_end"])
print("Selected code SHA256:", selected["snapshot_sha256"])Inspect
sections[0].source.provenance.snapshot.text in the JSON: it should contain only the selected function. Remove secrets, private input data or personal information before transmitting code. To publish, follow chapters 4–7 to set your actual project UUID and connection, then explicitly call publish(). Open Code and execution sources → View preserved code on the published section to reach its lines. The read-only viewer checks the result's current permissions and never runs code.The downloaded
walkthrough.py also supports python walkthrough.py --include-source, selecting metric, plot and other relevant definitions. This still saves locally by default. Sending to a real project additionally requires --project and --publish.24.3 Complete helper syntax and defaults
| Call | Defaults and contract |
|---|---|
repro.source.file(path, *, root, line_start=1, line_end=None, snapshot=False, repository_url=None, role="computation") | Select an existing range in a .py file. line_end=None means the final line. The actual range must exist within a file under root |
repro.source.function(function, *, root, snapshot=False, repository_url=None) | Select the saved definition of a function/class with an accessible source file. Role is definition. For dynamic/virtual cells, select the actual saved notebook cell |
repro.source.registration(*, root, snapshot=False, repository_url=None) | Capture this helper's call site as registration; it does not discover computation code |
repro.source.notebook(path, cell_id, *, root, provider="jupyter", notebook_url=None, snapshot=False, repository_url=None, role="definition") | Select one saved .ipynb code cell with the actual matching identity. provider="colab" is supported. Use role="reference" when identity with an earlier execution is uncertain |
root is an explicit existing directory boundary. Resolved paths and symlinks outside it are rejected. No directory traversal or upload is performed. One selected file may be at most 1 MiB. Each preserved reference allows 32 KiB and 1,000 lines, with a 256 KiB aggregate across the page and section copies. Inherited page-source copies count too; select small ranges only for relevant sections. The 16 MiB bundle limit and project storage policy also apply.24.4 Exact GitHub line links
Set
root to the actual repository root and supply your real repository_url="https://github.com/organization/repository". The helper reads local HEAD and the selected file, and builds a commit-pinned URL only when their bytes match. For Python the form is .../blob/<exact-commit>/<file>#Lstart-Lend. Modified files, non-Git directories and unknown identity do not receive an automatic pinned URL. An explicit snapshot still preserves the selected text in LUNA. Git remote credentials are never automatically collected. Byte differences, including CRLF/LF, are not claimed as a match.A GitHub notebook-file URL is not represented as an exact executable notebook-cell link. The saved file, selected cell text and cell identity can be inspected, while execution-environment navigation uses its provider-specific URL. External repository permissions remain separate from sharing a LUNA result.
24.5 Select a real Colab or Jupyter cell
Save a notebook copy as an
.ipynb file accessible to your runtime. Jupyter uses the cell's top-level id; Colab uses its metadata.id. They may differ. Do not substitute a displayed cell number or execution counter. The following pattern requires your actual saved file and an existing cell ID. Replace every file, ID and URL with your own values.from pathlib import Path
import luna_repro as repro
notebook_path = Path("saved_notebook.ipynb")
selected = repro.source.notebook(
notebook_path, "ACTUAL-COLAB-CELL-ID",
root=notebook_path.resolve().parent,
provider="colab",
notebook_url="https://colab.research.google.com/drive/ACTUAL-NOTEBOOK-ID",
snapshot=True,
role="reference",
)After matching a saved Colab cell, the helper constructs
#scrollTo=<metadata.id>. notebook_url must contain no query or existing fragment. The helper does not use hidden Colab APIs to discover the currently executing cell, and assembled links are not reported as browser-verified. Missing or duplicated cell identities fail. Unsaved edits, another copy or deleted cells can differ from the original execution; preserve a snapshot and state those limits.In
walkthrough.ipynb, INCLUDE_SOURCE defaults to False. Upload a saved notebook to the runtime, set SOURCE_NOTEBOOK, SOURCE_PROVIDER and SOURCE_CELL_ID to actual values, change the flag to True, then run the compute/save cell. SOURCE_NOTEBOOK_URL=None avoids guessing an external execution link. Notebook outputs, attachments and live global variables are excluded from the selected-code snapshot.24.6 Older results, AI and recovery
Old filename/line references remain unchanged and are not portrayed as new snapshots. Each fixed revision opens its own preserved code. Ordinary AI context, evidence downloads and Notion delivery do not automatically include code text. Only the report AI option Include code text adds the selected preserved snapshots that current permissions allow. Missing code stays explicitly missing, and arbitrary external URLs are not fetched. Identity with an earlier execution, data consistency, independent reproduction and research success need separate evidence.
For
invalid_source_snapshot, reconstruct the selection, range and hashes. For source_snapshot_limit, select smaller functions/cells. SDK retries for a result in Trash return result_trashed and do not restore it automatically. Restore your result in the platform, then explicitly retry its saved outbox. Revoked access or Trash state also blocks old code links through current authorization checks.25. Compose a report with results and narrative cells
1. Open a page under Reports → Reproducibility results.
2. Select the chart, table or metric sections you need, including sections from other result pages.
3. Open Review selection and proceed to compose the report.
4. Enter a title and use + Narrative cell before or after a result.
5. Write Markdown such as
## Background, ## Methods, ## Analysis and ## Limitations.6. Preview formatting with the editor tools. Reorder results and commentary with the up/down buttons, or drag the move handle on desktop.
7. Use Select more results to add sections from another page. On return, check that your title and commentary are preserved.
8. Choose Save platform report. The report starts as a private draft.
Use any arrangement that fits the study; none of these headings is mandatory.
Background and research question ← narrative cell
Experiment A render ← result cell at a fixed version
Data and evaluation methods ← narrative cell
Experiment B metrics ← result from another page
Comparison, limitations, next test ← narrative cellRemove only removes a cell from this report. It does not change its source. To correct measured values, review the actual research output and register a new result version. An existing report continues to reference the version selected earlier.
After saving, open Version history to inspect and restore earlier titles, cell order and content. Restoration adds a new revision. If another browser window has edited the report, review its current version first. Reading a report also checks your current access to all referenced results and background evidence.
26. Draft from research context with AI
1. Choose Save and draft with AI in the editor. This saves the current title and cells first.
2. Select earlier materials or reports that provide the research background. Only currently accessible materials in the same lab are available; use search if needed.
3. Add a precise instruction, for example: “Distinguish training-view PSNR from held-out performance, and discuss the failed camera check.”
4. Opt into images or saved code only when their actual content should be analyzed. The request uses at most 3 images and 24,000 selected code characters, with input coverage shown in the preview. A source link alone is not treated as reading code.
5. Review the report version, selected evidence, input scope and existing AI policy in the preview. Previewing does not execute AI.
6. Confirm the request to place it on the existing AI queue. The screen shows actual progress; status polling pauses when the tab is hidden and slows after errors.
7. Read the proposed title and narrative cells. Apply selected cells or all of them. This cannot change source image or metric values.
8. Review, edit and save the result yourself. Use Improve this cell with AI to refine one narrative cell.
Suggested content includes background, methods, data, experimental conditions, analysis, limitations and discussion. Unsupported details remain questions to verify. Do not treat generated interpretation as a confirmed finding, statistical validation or independent reproduction.
Cost and input scope: Generation uses existing AI access, daily allowance and request policy. Reading, editing and previewing do not make an additional AI call. Selecting images or code sends those selected inputs to the configured AI provider. Entire repositories, environment variables, keys and datasets are not collected automatically. External URLs require separate tools and current access.
If the report changes: A draft cannot overwrite a report or evidence that changed after generation. Review the current content and prepare another request. Errors and timeouts are not displayed as success; another request requires reviewing the applicable budget.
27. Move results to Trash and restore them
1. Open ⋯ on a result card you own or on its detail page.
2. Choose Move to Trash.
3. Review affected report references and Notion delivery states, then confirm the move.
4. Check that the result is hidden from normal lists and searches.
5. Open Trash from the result list and restore it. The same URL, ID, versions and images return.
Trashing a referenced result preserves report content and reference history. Reads recheck current source access, so reports or AI cannot bypass a hidden source. External Notion copies are not automatically deleted.
If the SDK returns
result_trashed, do not repeatedly retry. Explicitly restore your result in the platform, then retry the same outbox request. SDK retries cannot clear the trash state or resurrect a result by publishing a new version.Inspect any actively sending Notion job first. Pending jobs can be stopped; cancellation or erasure of an already transmitted external write is not guaranteed. Permanent erasure of reproducibility evidence is not provided, and moving it to Trash does not free its storage quota.
28. Continue the same report in ChatGPT or private AI consultation
This feature uses the real
consultant_thread_prepare and consultant_thread_commit tools. Check whether the current host exposes them. Server support and host tool availability are separate facts. Do not invent absent tool names or claim an unexecuted operation completed. If the tools are unavailable, continue through the same web report editor URL.The outer envelope is always
operation="save", values={"repro":{"operation":"operation below","values":{...}}}. Use canonical IDs obtained from actual search/read results.| Inner operation | Values and effect |
|---|---|
read | page_id, optional revision, section_key, offset. Existing fixed-result read; code text is excluded by default |
source | page_id, revision, section_keys array, include_code=true, optional offset. Explicitly read selected preserved code only; never fetch or execute an external URL |
report_read | report_id, optional revision, offset. Read the same report cells, Markdown, current revision and history. body is JSON text; follow next_offset when present |
report_save | title, cells, and a stable new-request UUID request_key. For an edit also provide report_id and its current revision. New reports use revision=0. Preserve prepared commentary and result references without a platform AI call |
ai_prepare | report_id, base_revision, request_key. Optional sources array of record:UUID/report:UUID, images=false, code=false, target commentary-cell UUID, instruction up to 600 characters and language ko/en. Preview a separate metered platform AI draft |
ai_read | run_id. Read queued/running/failed/ready draft state. Reading does not retry AI |
ai_apply | run_id, selected proposal-cell UUID array selected, stable request_key, optional use_title=true. Preview adopting selected commentary into the existing report |
A result cell is
{"id":"cell UUID","kind":"result","selection":{"page_id":"result UUID","revision":1,"section_key":"metrics"}}; it does not rewrite copied metrics or images. A commentary cell is {"id":"cell UUID","kind":"markdown","text":"Interpretation","origin":"human or ai","references":["record:material UUID"]}. Substitute actual UUIDs and preserve existing cell IDs. The same web limits apply: 100 cells, 40 result cells, 12,000 characters per commentary and 80,000 commentary characters total.Pass the exact returned review and preview_token to
consultant_thread_commit. Current domain access and luna:consultant:write plus luna:report:write are rechecked. Retrying the same approved request does not create another revision. If the report or evidence changed, reread it and prepare a fresh preview. Saving commentary already written in ChatGPT with report_save does not make a second platform AI call. Committing ai_prepare requests additional platform generation and must be treated separately. AI commentary is not auto-adopted: select it through ai_apply. None of these operations expands sharing, publishes to Notion, runs a GPU or establishes independent reproduction.29. Connect once and choose results in the final cell
29.1 Connection cell → computation → selection → preview → send
Choose a project in Connect results, then select Copy connection cell. Prepare the SDK and approve the browser connection in your first cell, run your existing computation, and finish with
repro.select(). It recommends supported objects still available in the caller's local scope. At notebook top level this is the notebook scope; inside a function it is that function's locals. It does not read variables from an old kernel or another process.If notebook widgets are available, candidates appear with checkboxes. Recommended items may be checked initially, but nothing has been sent. Confirm the items and adjust titles, descriptions, order and conversion options. Use Preview to inspect actual values, tables and images, then Send reviewed. Changing a choice or option requires a new preview. If only a candidate list appears or
ipywidgets is unavailable, use the equivalent code workflow below. The SDK does not automatically install display packages.Preview freezes the selected local values. Later mutation of the original variables cannot change that reviewed bundle. To send new calculation values, make a fresh selection and preview it. Repeating publication on the same Selection reuses its request identity; calling
repro.select() again creates another selection.29.2 A complete local exercise without extra libraries
After installing the SDK, run this unchanged. It uses a practice project UUID and saves only HTML and JSON: no authentication, network or platform creation.
from pathlib import Path
import luna_repro as repro
repro.configure(project="12345678-1234-5678-1234-567812345678")
metrics = {"MAE": 0.5, "samples": 3}
comparison = [[0, 0.0, 0.5], [1, 1.0, 1.5], [2, 2.0, 2.5]]
selection = repro.select(
namespace={"metrics": metrics, "comparison": comparison},
title="Local selection practice", show=False,
)
print(selection.summary()) # Candidate names/types/reasons, not complete source values
selection.choose("metrics", "comparison")
selection.option("comparison", columns=["index", "reference", "prediction"])
selection.edit(description="Three synthetic values, not actual research performance.",
order=["comparison", "metrics"])
folder = Path(".luna-repro") / "selection-practice"
selection.preview(folder / "preview.html")
selection.save(folder / "selected.json")
print("Local preview:", folder / "preview.html")Open
preview.html in a browser and inspect its order and values. To publish, connect to your actual project with repro.connect(), construct and review a new Selection for that project, then call selection.publish(). Never publish with the practice UUID. Preview files and the outbox can contain private research results; store them privately.29.3 Choose table, array and image conversions explicitly
| Result | Default handling and required choices |
|---|---|
| Number or numeric metrics dictionary | Metrics; no judgment of success or improvement |
| Row list or pandas DataFrame/Series | Table; select columns, row limit and whether to retain the index |
| NumPy array | Bounded 1D/2D tables; image interpretation needs as_image=True and relevant range/layout choices |
| PyTorch Tensor | No automatic CPU transfer; select a small value and explicitly set allow_cpu=True |
| PNG/JPEG Path, PIL Image or matplotlib Figure | Convert the selected image/figure; do not traverse an entire directory |
| Plotly Figure | Needs an available static-image exporter; otherwise save a PNG/JPEG yourself and select that file |
For an existing
results_df, reduce the selected table as follows. Replace score and method with actual column names.selection = repro.select(namespace={"results": results_df}, show=False)
selection.choose("results")
selection.option("results", rows=50, columns=["method", "score"], index=False)
selection.preview(".luna-repro/results-preview.html")A reduced table is not the complete dataset. Check omitted rows, failed cases and warnings, and state those limits in interpretation. Recommendations use local type, size and name information; they are not AI judgments of scientific importance or a search for favorable results.
purpose="accuracy comparison" is a local ranking hint matching purpose words against candidate names. Default recommendations make no AI call and incur no AI charge.29.4 Python files and figures that close
An ordinary Python file or terminal prints candidate metadata instead of notebook checkboxes. Use
show=False, choose() and preview("path.html"). A server without a browser can still print an approval URL to open in your own browser. Unattended jobs use previously approved secret management and selection rules. Installation, preview and reading do not publish.If a matplotlib figure disappears during
show() or close(), open an explicit scope before computation. It retains bounded figures, warning-category counts and failure state, not all stdout, raw error messages or data. Do not run overlapping capture scopes.import matplotlib.pyplot as plt
with repro.capture(max_figures=4) as captured:
plt.plot([0, 1, 2], [0, 1, 4])
plt.show()
plt.close()
captured_selection = captured.select(show=False)
captured_selection.preview(".luna-repro/captured-preview.html")Unsupported or over-limit figures can be omitted. Review warnings, dropped figures and failure state in
capture_status alongside the images. A scope cannot recover a figure that vanished before it started. For exact computation provenance, use sources={"candidate_name": source_ref} or Page/Section sources described in sections 12 and 24. An automatic registration location is not the calculation location.29.5 Saved selection rules are optional
After reviewing,
selection.save_rule("selection-rule.json") stores variable names/types, ordering and conversion options. Saving does not send. Later apply it with repro.select(namespace=..., rule="selection-rule.json") and review again. Missing variables or changed types/projects stop the operation, so do not casually reuse a rule for different research.Unattended sending requires both
auto_publish=True when saving the rule and auto=True when invoking it. It sends once per invocation; it does not create a scheduler or endless retries. Rules contain no result values or connection key, but custom titles/descriptions can be private, so apply your research-storage policy.29.6 Continue to platform preview, reports and Notion
Open the successful publication URL and use Full preview to inspect selected results in order. Compact provenance on a result card links to code; expand details only when needed. Missing provenance or a reference link to an original notebook is not proof of the executing code. Opening a link does not execute it.
Combine result sections into a report and add narrative cells. Publish to Notion opens the destination and automatic preview before publication. Confirm remote success with its receipt; uncertain delivery does not automatically repeat. Connection, recommendations and report preview do not run paid AI or GPUs. AI drafting follows section 26's policy and selected evidence.
30. Read results, refine one cell and publish to Notion
30.1 Consistent reading and sharing tools
Use Share, Print and export and Favorite at the top of a result page. Translation covers titles, narrative and captions while preserving code, URLs and measured values. Show original restores the original text; existing free/AI translation policies apply. Sharing, favorites and print retain the revision being viewed. Copying a link grants no additional access.
Ordinary and result-based reports place Edit and Publish to Notion beneath the title. Generated report bodies use View result and code instead of repeated internal filenames, hashes and registration locations. View code opens the supplied line or cell; Source details retains original filenames, preserved code and hashes. Opening a link never executes code. Existing manually edited bodies and version histories remain intact.
30.2 Refine exactly one narrative cell
1. Select results to compose a report, or choose Edit on an existing result report.
2. Add a narrative cell and write a short request, for example: “Explain the RMSE difference and include the limitation of a small sample.”
3. Type
[[ to find and select a source material or report. Type @ to select a researcher mention.4. Choose Refine this cell with AI. This is one AI request under existing permissions, budgets and daily allocations. Quick cell refinement does not automatically include images or source-code text.
5. Follow the actual queued/generating/ready state and elapsed time beside the cell. Polling pauses in hidden tabs; reloading resumes observation of the same job. Repeated clicks do not create duplicate paid requests.
6. If the text is unchanged, the suggestion applies only to that draft cell. It does not change the title, other cells or result order. Use Undo to restore the original. If you edited during generation, compare before applying.
7. Review the full preview and choose Save platform report. AI refinement alone does not save a report or a report revision.
Use the separate Save and draft with AI action to structure a whole report. Explicit material/report citations become readable source evidence and retained access dependencies on save. The selected results' project/grant objectives also provide context. For another project's objectives or unsupported document types, cite a readable material/report from that project instead. Researcher mentions identify people; they do not authorize reading private material. Unsupported or inaccessible citations provide an actionable message.
30.3 Finish in one publication panel
The image/table conversion and append options below apply to reproducibility results and result-based reports. Ordinary reports share the publication panel, with the supported options and preview scope shown there.
Choose Publish to Notion, review the destination and automatic preview, then Publish to Notion. The title is filled in and the preview shows narrative, tables and images. Publication options changes the title, introduction and new-child/append behavior; changes regenerate the preview.
New exports support up to 40 sections, 10 images of at most 8MiB each, and tables of 40 columns/99 data rows. Long bodies split into at most 20 chunks, retaining confirmations for each chunk. Image preparation and upload requests are separate. Image preparation and body publication show real progress. Closing the panel preserves accepted jobs. Follow specific guidance for access, size limits or expired previews. An Unconfirmed outcome may already have reached Notion and is not automatically repeated. Follow the available confirmation actions shown in the panel. Open in Notion or Check publication status is offered when the publication location is known. Copies follow the destination's Notion audience; revoking LUNA access does not remove them.
30.4 Try it yourself
Start with the synthetic example. Sign in, choose a project in Connect results, and select Try a synthetic example. Compose private example results, add narrative cells, move them and inspect the full preview. Those steps do not call AI, run a GPU or publish to Notion. AI refinement and publication are separate explicit actions. Downloadable HTML, Markdown and practice ZIP manuals include this guidance.