# Getting Started with nblite

This guide walks you through creating your first nblite project, from installation to publishing a Python package.

## Prerequisites

- Python 3.9 or higher
- pip or uv package manager
- Jupyter Notebook or JupyterLab (recommended for editing notebooks)

## Installation

Install nblite using pip:

```bash
pip install nblite
```

Or with uv:

```bash
uv pip install nblite
```

Verify the installation:

```bash
nbl --version
```

## Creating Your First Project

### Step 1: Initialize the Project

Create a new directory and initialize an nblite project:

```bash
mkdir mylib
cd mylib
nbl init --name mylib
```

This creates the following structure:

```
mylib/
├── nblite.toml     # Configuration file
├── nbs/            # Directory for notebooks
└── mylib/          # Python package directory
    └── __init__.py
```

### Step 2: Understand the Configuration

Open `nblite.toml` to see the default configuration:

```toml
# nblite configuration
export_pipeline = "nbs -> lib"

[cl.nbs]
path = "nbs"
format = "ipynb"

[cl.lib]
path = "mylib"
format = "module"
```

This defines:
- **Export pipeline**: Notebooks in `nbs/` export to modules in `mylib/`
- **Code locations**: `nbs` for notebooks, `lib` for Python modules

### Step 3: Create Your First Notebook

Create a notebook for your core functionality:

```bash
nbl new nbs/core.ipynb --title "Core Module"
```

This creates a notebook with:
- A `#|default_exp core` directive (sets the export module name)
- A markdown title cell

### Step 4: Write Code in the Notebook

Open the notebook in Jupyter and add your code. Use the `#|export` directive to mark cells for export:

**Cell 1** (already created):
```python
#|default_exp core
```

**Cell 2** (markdown):
```markdown
# Core Module

This module provides the core functionality for mylib.
```

**Cell 3** (code):
```python
#|export
def add(a: int, b: int) -> int:
    """Add two numbers together.

    Args:
        a: First number
        b: Second number

    Returns:
        The sum of a and b
    """
    return a + b
```

**Cell 4** (code - testing, not exported):
```python
# Test the function
add(2, 3)  # Should output 5
```

**Cell 5** (code):
```python
#|export
def multiply(a: int, b: int) -> int:
    """Multiply two numbers together."""
    return a * b
```

**Cell 6** (code):
```python
#|export
class Calculator:
    """A simple calculator class."""

    def __init__(self, initial_value: int = 0):
        self.value = initial_value

    def add(self, n: int) -> "Calculator":
        """Add to the current value."""
        self.value += n
        return self

    def result(self) -> int:
        """Get the current value."""
        return self.value
```

### Step 5: Export to Python Module

Run the export command:

```bash
nbl export
```

This creates `mylib/core.py`:

```python
# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/core.ipynb

__all__ = ['add', 'multiply', 'Calculator']

# %% ../nbs/core.ipynb 2
def add(a: int, b: int) -> int:
    """Add two numbers together.

    Args:
        a: First number
        b: Second number

    Returns:
        The sum of a and b
    """
    return a + b

# %% ../nbs/core.ipynb 4
def multiply(a: int, b: int) -> int:
    """Multiply two numbers together."""
    return a * b

# %% ../nbs/core.ipynb 5
class Calculator:
    """A simple calculator class."""

    def __init__(self, initial_value: int = 0):
        self.value = initial_value

    def add(self, n: int) -> "Calculator":
        """Add to the current value."""
        self.value += n
        return self

    def result(self) -> int:
        """Get the current value."""
        return self.value
```

Notice:
- The `#|export` directives are removed
- An `__all__` list is generated automatically
- Cell references are added as comments

### Step 6: Use Your Package

You can now import and use your package:

```python
from mylib.core import add, Calculator

print(add(2, 3))  # 5

calc = Calculator(10)
calc.add(5).add(3)
print(calc.result())  # 18
```

## Next Steps

### Fill Notebook Outputs

Execute notebooks and save their outputs:

```bash
nbl fill
```

This is useful for:
- Generating output cells for documentation
- Verifying notebooks run correctly
- Creating reproducible results

### Clean Notebooks

Remove outputs before committing to version control:

```bash
nbl clean -O
```

### Set Up Git Hooks

Automate cleaning and exporting on commit:

```bash
nbl install-hooks
```

### Generate Documentation

Build documentation from notebooks:

```bash
pip install mkdocs mkdocs-material mkdocs-jupyter
nbl render-docs
```

### Create More Notebooks

Organize your code across multiple notebooks:

```bash
nbl new nbs/utils.ipynb --title "Utility Functions"
nbl new nbs/io.ipynb --title "Input/Output"
```

## Common Workflows

### Development Workflow

1. Edit notebooks in Jupyter
2. Run cells interactively to test
3. Mark production code with `#|export`
4. Run `nbl export` to generate modules
5. Run `nbl fill` to capture outputs
6. Commit changes

### CI/CD Workflow

```bash
# Test that notebooks execute without errors
nbl test

# Export and verify
nbl export
python -m pytest tests/

# Generate documentation
nbl render-docs
```

### Full Preparation

Run all steps at once:

```bash
nbl prepare
```

This runs:
1. Export notebooks
2. Clean notebooks
3. Fill outputs
4. Generate README (if configured)

## Tips for Success

### Keep Notebooks Focused

Each notebook should focus on one module or concept. This makes:
- Code easier to find
- Reviews more manageable
- Testing more targeted

### Use Clear Module Names

The `#|default_exp` directive sets your module path:

```python
#|default_exp mylib.utils         # Creates mylib/utils.py
#|default_exp mylib.io.readers    # Creates mylib/io/readers.py
```

### Separate Exploration from Production

Not all code in a notebook needs to be exported. Use exports strategically:

```python
#|export
def production_function():
    """This goes to the module."""
    pass

# Exploration code - not exported
data = load_sample_data()
production_function()
visualize_results(data)
```

### Document As You Go

Notebooks naturally combine code and documentation. Take advantage of this:

```python
#|export
def complex_algorithm(data):
    """
    Implements the XYZ algorithm.

    This algorithm works by:
    1. First step
    2. Second step
    3. Third step

    Args:
        data: Input data array

    Returns:
        Processed results
    """
    pass
```

## Troubleshooting

### "No nblite.toml found"

Make sure you're in the project root directory, or use the `--config` flag:

```bash
nbl --config /path/to/nblite.toml export
```

### "Module not found" after export

Check that:
1. Your `#|default_exp` matches your expected module path
2. The `[cl.lib]` path in `nblite.toml` is correct
3. You have an `__init__.py` in the package directory

### Outputs not appearing in notebooks

Run `nbl fill` to execute notebooks and save outputs:

```bash
nbl fill --fill-unchanged  # Force re-execution
```

## Further Reading

- [Configuration Guide](configuration.md) - All configuration options
- [CLI Reference](cli-reference.md) - Complete command documentation
- [Directives Reference](directives.md) - All notebook directives
- [Export Pipeline](export-pipeline.md) - How export works in detail
