Quick Start

From nothing to a running menu bar app in three commands.

Create a project

nib create myapp
cd myapp
myapp/
├── src/
│   ├── main.py          # entry point
│   └── assets/          # icons, images, fonts
├── pyproject.toml       # metadata and build settings
└── README.md

src/main.py is a small counter app:

import nib


def main(app: nib.App):
    app.title = "Myapp"
    app.icon = nib.SFSymbol("star.fill")
    app.menu = [
        nib.MenuItem("Quit", action=app.quit),
    ]

    counter = nib.Text("0")

    def increment():
        counter.content = str(int(counter.content) + 1)

    app.build(
        nib.VStack(
            controls=[
                nib.Text("Hello, Myapp!", font=nib.Font.title),
                counter,
                nib.Button("Click me", action=increment),
            ],
            spacing=16,
            padding=24,
        )
    )


nib.run(main)

pyproject.toml records the entry point and the build settings. Every option is documented in the pyproject.toml reference.

[project]
name = "myapp"
version = "0.1.0"
requires-python = ">=3.10"
dependencies = ["pynib"]

[tool.nib]
entry = "src/main.py"

[tool.nib.build]
name = "Myapp"
# identifier = "com.example.myapp"
# icon = "src/assets/icon.png"

Run it

nib run

An icon appears in the menu bar; click it to open the popover. nib run reads the entry point from pyproject.toml, launches the Swift runtime once, and reloads your Python code every time you save a .py file. Pass a script path to run something else, or -r to also watch subdirectories. Details: nib run.

Build it

nib build

This produces dist/Myapp.app: a standalone bundle with its own Python interpreter, your code and dependencies, the runtime, and an Info.plist generated from pyproject.toml. Details: nib build.

Next