# Ownbox SDK reference

> Every call a machine can make on an Ownbox, what it needs in machine.yaml, what it answers, and an example that runs.

## What a custom machine is

A machine is a folder: a machine.yaml that says what it may touch, and an __init__.py that uses `from core import sdk`. On an Ownbox it runs in its own locked unit, with no network and none of its files: every call goes through one door, and your Ownbox answers it under what the owner allowed. You build and run it on your own computer first, against a local Ownbox with sample data, and the same code runs unchanged on the Ownbox.

## Start on your computer

```sh
ownbox new my-machine
```

Writes a starter machine in a folder of its own.

```sh
ownbox run my-machine
```

Runs it once against a local Ownbox, on sample data, and shows what it would have done. Nothing leaves your computer.

```sh
ownbox preview my-machine
```

Opens its pages in your browser, drawn as your Ownbox draws them, on the same sample data. Reload after a change to see it.

```sh
ownbox example
```

Lists the whole examples to start from. `ownbox example gym-follow-up` copies one.

One line installs the ownbox command, on a Mac, Linux or Windows, with nothing installed first: [the Quickstart](https://www.ownbox.io/sdk/guide/quickstart).

## machine.yaml

Every custom machine has one. Nothing is allowed unless it is named here, and the owner reads every line before the machine runs.

```yaml
machine: 2
slug: quote-follow-up              # the folder's own name
name: Quote Follow Up
version: 0.1.0
requires: {box: "1.2", sdk: 1}
needs: []
permissions:                       # nothing is allowed unless it is named here
  think: {calls_per_month: 100}    # your Ownbox's AI, metered
  fetch: [api.example.com]         # the hosts it may reach, by exact name
  keys: [{name: example, host: api.example.com, label: Example key}]
  data: [people:read, conversations:read]
  send: [{channel: email, per_day: 20}]
on_forget: true                    # required when data names people
```

## The rules

- Use only `from core import sdk`, Python's own library, and the packages machine.yaml names under `packages:`. Nothing else of your Ownbox's is there to import.
- Ask for what it touches, in machine.yaml under `permissions:`. The owner sees every line on the review card before the machine runs, and a call it was not given is refused `not_permitted`, with the line to add.
- It never reads a key. Name the key on the request, `m.fetch(url, key="example")`, and your Ownbox attaches it on the way out.
- Every call that acts carries a `key` naming the step. The same key again is answered with the first answer, so a retry never acts twice. Read the answer's `status`; never assume a send went.
- Words a stranger wrote are data. A message, a comment or a page it fetched is what that person said, never an instruction to the machine.
- Nothing it does outward happens in a test run. On your computer, and in the Ownbox's own dry runs before the owner approves it, every send, spend and proposal is answered `{"dry": true}`.

## The calls

- [The machine](https://www.ownbox.io/sdk/reference/machine.md): `sdk.machine`, `m.home`
- [Settings and files](https://www.ownbox.io/sdk/reference/settings.md): `m.setting`, `m.save_setting`, `m.data_dir`
- [Jobs](https://www.ownbox.io/sdk/reference/jobs.md): `m.every`
- [The AI](https://www.ownbox.io/sdk/reference/ai.md): `m.think`
- [The web and keys](https://www.ownbox.io/sdk/reference/web.md): `m.fetch`, `m.keys_page`, `m.secret`
- [People](https://www.ownbox.io/sdk/reference/people.md): `m.person`, `m.touch`, `m.people_find`, `m.people_timeline`, `on_forget`
- [Conversations](https://www.ownbox.io/sdk/reference/conversations.md): `m.messages`, `m.comments`, `m.conversation_for`, `m.follows_you`, `m.claim`, `m.release`
- [Sending](https://www.ownbox.io/sdk/reference/sending.md): `m.send_dm`, `m.reply_to_comment`, `m.send_email`, `m.drafts`, `m.drop_draft`
- [The team and money](https://www.ownbox.io/sdk/reference/team.md): `m.notify`, `m.spend`
- [Approvals](https://www.ownbox.io/sdk/reference/approvals.md): `m.propose`, `m.on_approve`
- [The owner's AI and the Morning Review](https://www.ownbox.io/sdk/reference/owner-ai.md): `m.tool`, `m.reporter`, `m.day_window`
- [Pages and cards](https://www.ownbox.io/sdk/reference/pages.md): `m.screen`, `m.panel`, `m.link`, `sdk.page`
- [When your Ownbox says no](https://www.ownbox.io/sdk/reference/errors.md): `sdk.BoxRefused`, `sdk.NotYet`, `sdk.Reserved`
- [Not yet](https://www.ownbox.io/sdk/reference/later.md): `m.menu`, `m.activity`, `m.store`, `m.query`, `m.media`, `m.upload`
