# 4 · How-To / Setup > [3 · Configurability](3-configurability.md) is *what* you can configure. This is *how* to actually stand > it up — concrete tutorials. The recommended path throughout is **pull** (an always-on watcher on your own > machine); it needs no public infrastructure. Examples are generic — swap in your own tags, agents, and > paths. **The shape of a working setup, in four moves** (one tutorial each below): 1. A **synced vault** your agent can reach. 2. A **trigger** defined (a tag bound to an action) in `config/triggers.json`. 3. The **always-on watcher** running — the one piece that catches a tag and launches your agent. 4. Your **agent integrated** into your system so it knows to use Int.ai and how. --- ## Tutorial 1 — Get the vault synced across your devices The **app provisions the vault and the sync.** You (one-time): install the Int.ai app, sign in to iCloud (the default transport). The app creates the vault on your phone and iCloud mirrors it to your Mac — it shows up as a folder in iCloud Drive. Nothing to build; this is what makes "capture on the phone, act on the Mac" work. **Your agent's job is the rest — so you don't hand-edit files:** 1. **Locate the synced vault** on your computer (the iCloud Drive folder the app created). Resolve it once and remember the path. 2. **Confirm / scaffold the structure** (see [2 · Infrastructure](2-infrastructure.md) for the full layout). A complete vault has: ``` vault/ ├── canvases//{canvas.json, nodes/, edges/} ├── notes/ ├── assets/ ├── config/triggers.json └── .intai/ ``` If a piece is missing, your agent can create it (e.g. an empty `config/triggers.json` containing `[]`). 3. **Seed it (optional).** Your agent can create a starter canvas or note so you open the app to something ready, instead of a blank slate. > **Transport is your choice.** iCloud is the default, but the vault is just files — point Dropbox, > Syncthing, git, or any sync at the same folder and it works identically. Cross-platform (no Mac) → use > one of those instead of iCloud. --- ## Tutorial 2 — Set up a trigger (what your agent edits, and how) **Triggers live in one file: `config/triggers.json`** — a JSON **array** of trigger objects. This is the file your agent edits to create or change triggers. (Unlike nodes, which are one-file-each, all triggers share this single list — so read it, modify the array, write it back whole.) A trigger object's fields: | Field | Required | Meaning | |-------|----------|---------| | `id` | yes | Uppercase UUID, unique in the list | | `tag` | yes | The text that fires it, e.g. `#research` | | `label` | yes | Short human name (shown in the app's tag picker) | | `description` | no | What it's for (shown in the app) | | `color` | yes | Hex color applied to the tagged node — and to your agent's reply node | | `action` | yes | `webhook` (dispatch to your system) · `holdback` (park the node) · `signal` (pure meaning, fires nothing) | | `webhook_url` | no | **Its presence chooses the transport:** *absent* → pull (your watcher catches it); *present* → push (Int posts to that URL) | | `instructions` | no | A per-trigger prompt carried to your agent when it fires — *this is where a lot of behavior config lives, with no code* | **To add a pull trigger,** append an object with **no `webhook_url`:** ```json { "id": "B7F3A1C2-0000-4D5E-8A9B-1122334455AA", "tag": "#research", "label": "Research", "description": "Kick off a research pass on this capture", "color": "#3B82F6", "action": "webhook", "instructions": "You were activated because the user tagged this node #research. Research the topic in the node and write a concise brief back. Do not include any #hashtags in your reply." } ``` - The **`instructions` field is your behavior lever** — change what a tag *does* by editing this string, no redeploy. (Want essays? Terse bullets? A specific job? Say so here. See [3 · Configurability → how your system responds](3-configurability.md).) - **Full parity with the app:** anything you write here, the user can also set on the triggers screen, and vice-versa. They're the same file. - **Add `webhook_url`** only if you want the **push** path (Tutorial 3, end). --- ## Tutorial 3 — Build your always-on watcher (a spec to implement) The pull path needs one always-on process — the **watcher** — on your computer. Rather than depend on a black box, **build your own** (or have your agent build it): it's roughly a hundred lines in any language, and owning it means you can shape it however you like. Here is the spec to implement. **Purpose.** Watch the vault; when a capture gains a pull-trigger tag, launch the user's agent on that capture and write the reply back to the canvas. (Nothing can wake a program that's off — this process *is* the always-on piece the whole pull path depends on.) **Configuration it needs:** - The **vault path** (from Tutorial 1). - The **pull triggers** from `config/triggers.json` — those with `action: "webhook"` and **no** `webhook_url`. - A **map of `tag → working directory`** — which folder to launch the agent from, per tag. - A poll interval and a spawn timeout. **The loop (every few seconds):** 1. Read every node file across every canvas. 2. **Skip** any node with `source: "agent"` — never react to your own write-backs. 3. For each remaining node, check whether its text contains a watched pull tag. 4. **Dedup:** handle each `(node id, tag)` pair only once; persist what you've fired so a restart doesn't replay it. 5. On a *new* match, **launch the user's agent** from the mapped directory, headless, passing the node's text plus the trigger's `instructions` as the prompt (e.g. `claude -p ""`, with stdin ignored so it can't block). 6. Capture the reply; **strip any `#tags`** from it (loop guard). 7. **Write the reply back** as a new node beside the original — `x + 250`, same `y`, `source: "agent"`, the trigger's `color`, uppercase-UUID filename = `id` (the hard contract, [doc 3](3-configurability.md)). **Required behaviors — don't skip these:** - **Baseline on first run.** Mark all *already-tagged* nodes as seen so you never back-fire history; only tags that appear after startup fire. - **Mark-before-run.** Record a `(node, tag)` as handled *before* launching, so a crash mid-run can't double-fire. - **The cwd is load-bearing.** Launch from the agent's own directory so it boots with its `CLAUDE.md`, memory, and tools — that's what makes it *your* agent, not a blank assistant. Launch from the wrong place and you get a generic model with no context. - **Headless auth is its own step.** The spawned agent needs its *own* credentials (a headless login or API key); being logged in *interactively* does **not** guarantee an unattended process can authenticate. Verify a one-line headless run (have it reply `PONG`) **before** relying on the watcher. - **Stay running.** Register the process as a background service (e.g. a `launchd` agent on macOS) so it auto-starts at login and restarts on crash. - **Mind sync lag.** Phone→computer changes take seconds to a minute over iCloud; fire once the file lands locally. **Test it.** With the watcher running, create a **new** node tagged with a configured pull tag — your agent should reply beside it within a cycle or two. **Push variant (optional, for instant firing while away from your computer).** Instead of polling, add a `webhook_url` to the trigger and run a small reachable endpoint that Int posts to the moment you tag. **Secure it** — require a secret and reject anything without it. Pull is the recommended default: it needs no public address and survives your computer sleeping (the tagged file is still there on wake); push is the upgrade when immediacy matters. --- ## Tutorial 4 — Integrate Int.ai into your system Int.ai is the surface; your system is the brain. "Integrating" means wiring your agents so they **know to work through Int.ai, where the vault is, and how to act on it.** The recommended shape is **two layers:** **Layer 1 — a small, always-loaded pointer in your agent's own instructions.** In your agent's `CLAUDE.md` (or role/system file), keep a short block it always sees: - *That* it works through Int.ai, and **where the vault is** (the resolved path from Tutorial 1). - A **link to these docs** for the mechanics (Layer 2). - **Your** tag taxonomy (what each tag means) and **your** response preferences (voice, format, where replies land). This is *your* personalization — it doesn't belong in Int.ai's generic docs; it belongs here, in your system. **Layer 2 — the full Int.ai docs saved in your system, read on demand.** Drop this doc set into a folder your agent can read (e.g. an `Int.ai/` reference folder). When the agent actually needs the exact mechanics — the write format, how to add a trigger — it opens the relevant doc. It does **not** carry the whole manual in context; the Layer-1 pointer tells it where to look. **Why two layers:** the agent must *persistently* know Int.ai exists and where the vault lives (Layer 1), but the detailed reference is large and changes over time, so keep it queryable rather than inlined (Layer 2). You get reliability without token bloat or stale copies. **What it looks like in practice.** A coordinating agent in your system (whatever plays the "reads my incoming stuff and acts on it" role) treats the vault as an input: it picks up newly-tagged captures, follows your Layer-1 preferences for what to do, consults the Layer-2 docs for *how* to read/write correctly, and writes results back to the vault — which sync carries to your phone. > **This is our recommended method, not the only one.** You could inline everything into your agent's > instructions, route through a dedicated agent, or wire it some other way entirely — Int.ai imposes > nothing. The two-layer pattern is what we'd reach for: minimal always-on pointer + on-demand reference. > A future Examples doc will walk through a real integrated system end to end (deferred until we've tested > the live flow). --- ## You're wired Vault synced (1) → a tag that means something (2) → the watcher that catches it (3) → your agent that knows what to do with it (4). Tag a capture, and your system acts on it — on the canvas, in your hands, wherever you are.