> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bravenlab.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Direct logging

> Push results to Braven from your own scripts — wandb-style init / config / summary / upload / finish.

Use this when you already have analysis code and want to log results directly — no folder watcher, no pipeline.

```python theme={null}
import braven

braven.init(name="My Experiment", project="TCS3448")
braven.config("learning_rate", 0.001)
braven.summary("accuracy", 0.94)
braven.upload("plot.png")
braven.finish()
```

## `braven.init()`

Creates a new Experiment and sets it as the active run.

<ParamField path="name" type="str | None">
  Experiment name shown in the UI.
</ParamField>

<ParamField path="notes" type="str | None">
  Optional free-text description.
</ParamField>

<ParamField path="project" type="str | None">
  Project name as shown in the app. Required if you belong to more than one project.
</ParamField>

<ParamField path="company" type="str | None">
  Company name — only needed to disambiguate when the same project name exists under two companies.
</ParamField>

Returns a `Run`. Raises `RuntimeError` if neither `company` nor `project` is given, or if the name doesn't match anything you have access to.

<Note>
  `braven.init()` is dual-purpose: called with `name=`/`project=`/`company=` (or no pipeline-specific kwargs) it does **direct logging**. Called with `experiment_id=`/`api_url=`/etc. (the shape the worker uses) it instead does pipeline-mode setup — see [Pipeline scripts](/sdk-reference/pipeline-scripts). You won't hit this ambiguity in your own scripts; it only matters if you're reading the SDK source.
</Note>

## Run methods

Everything below works identically as a module-level call (`braven.config(...)`) against the currently active run, or as a method on the `Run` object `init()` returns.

<ResponseField name="run.config(key, value)" type="→ None">
  Log an input/configuration parameter, experiment-level.
</ResponseField>

<ResponseField name="run.summary(key, value)" type="→ None">
  Log an output metric, experiment-level.
</ResponseField>

<ResponseField name="run.device(key, type=None)" type="→ Device">
  Return a device-scoped handle — see [Devices](/concepts/devices). Memoised per run: repeated calls with the same key return the same handle, and the first call's `type` wins.
</ResponseField>

<ResponseField name="run.plot_series(name, y, x=None, x_label=None, y_label=None, mode='line')" type="→ None">
  Log a labeled data series as an interactive plot. Call again with the same `name` and a different `y_label` to group multiple traces onto one chart.
</ResponseField>

<ResponseField name="run.upload(path_or_fig, name=None)" type="→ None">
  Upload a file, or a live matplotlib `Figure`. For a Figure: saves the PNG (same as `fig.savefig()`) and best-effort extracts an interactive companion from its line/scatter data — see [Series vs. Figures](/concepts/data-model).
</ResponseField>

<ResponseField name="run.finish()" type="→ None">
  Flush metadata. Idempotent — safe to call once at the end via `braven.finish()`.
</ResponseField>

## Device methods

Obtained via `run.device(key)` or module-level `braven.device(key)`.

```python theme={null}
dev = braven.device("SENSOR-4471", type="Photodiode")
dev.config("bias_voltage", 3.3)          # alias for log_config
dev.summary("SNR", 14.2)                 # alias for log_summary
dev.log_series("response", values)
dev.plot_series("response_curve", y=signal, x=wavelength)
```

`dev.*` calls are tagged with that device's key; the same metric name (`"SNR"`) stays identical across every device — the device is a separate coordinate, never a name suffix like `SNR_dev1`.

## Multiple devices in one experiment

```python theme={null}
for sensor_id, snr in results.items():
    braven.device(sensor_id).log_summary("SNR", snr)

braven.summary("max_device_mismatch", spread)   # experiment-level, not tied to one device
```

## Full cheat sheet

```python theme={null}
braven.login(url, key)                       # once (or: python -m braven login)
braven.init(name=..., project=..., company=...)
braven.config(key, value)                    # input parameter
braven.summary(key, value)                   # output metric
braven.device(key, type=None)                # device-scoped handle
braven.plot_series(name, y, x=..., y_label=...)  # interactive chart
braven.upload(path_or_fig, name=...)         # file or matplotlib Figure
braven.finish()
```
