--- name: busabase description: Guide users through choosing and connecting to Busabase, authorizing Busabase Cloud when needed, and installing the Busabase Agent Skills for ongoing use. --- # Busabase β€” first-run setup This document walks you (the agent) β€” and through you, the user β€” from nothing to a working, populated workspace, then installs the permanent `busabase` and `busabase-app-creator` skills for everyday use and workspace app creation. The user already confirmed this edition in the preceding dispatcher (or entered through an authoritative Dashboard/local-app link). Work top to bottom, **in the user's language**, starting with connection. Do not welcome them again and do not ask them to choose an edition again. ## The journey at a glance β€” and how to run it You are guiding the user through four milestones. Existing users skip initialization entirely: | # | Milestone | Covered by | Done when | | - | --------- | ---------- | --------- | | 1 | πŸ”Œ **Connect** | Step 0 | a verified MCP integration, or device login, returns the selected Space | | 2 | πŸ—οΈ **Initialize if required** | Step 1 + Step 2 | version-0 Space gets starter data | | 3 | βœ… **Verify** | Step 2 | starter records read back and marker becomes version 1 | | 4 | πŸŽ“ **Skills installed** | Step 3 | both skills available in the agent's persistent skill store, πŸŽ‰ | **Conduct rules β€” these create the step-by-step feel; follow them at every turn:** - **Show progress at every milestone boundary.** When a milestone completes, open your next message with a one-line tracker (in the user's language), e.g. `βœ… Connect Β· β–Ά Initialize Β· β—‹ Verify Β· β—‹ Skill` β€” so the user always knows where they are and how much is left. Don't spam it mid-milestone; boundaries only. - **One question per message, lettered options whenever possible** (A/B/C/D…). Never two open questions at once, and never a question buried under a wall of output. If the user's answer is ambiguous, ask one short follow-up β€” still with options. - **Announce β†’ act β†’ confirm.** Before each action, say in one plain line what you're about to do and why. After it, confirm with a βœ… line what just became true ("βœ… Server is up", "βœ… Base created β€” your starter workspace is ready"). Never run several setup actions silently and dump the results. - **The user sees outcomes and choices, not commands.** Run the curl / install commands yourself; translate results into plain language. Only show a command when the user must run it (e.g. completing device authorization in the browser). - **Small numbered sub-plans for anything multi-part.** When a milestone has several moves (e.g. Step 2: inspect β†’ create β†’ seed β†’ verify), tell the user the mini-plan first ("three quick things: …"), then tick through it. Here is the first move. ## Step 0 β€” Connect to Busabase Cloud ### 0a. MCP first Ask the Harness to discover and use an existing Busabase MCP integration before CLI. Call "list_integration_tools" with "providerKey: busabase-cloud-mcp" to find the Busabase integration, if the tool exists. Verify it with a read-only identity and Space check; reconnect it first if configured but disconnected, and do not assume tool names. Target the Dashboard-selected Space `YOUR_SPACE_ID` in that first check. If access fails, ask the user to switch or reconnect accounts; never choose or create another Space. If verification succeeds, skip **0b** and keep MCP for this run. Otherwise use the CLI fallback. ### 0b. CLI fallback One move: sign in. The dashboard already chose the Space, so there is nothing to confirm afterwards. Sign-in is two commands, one per conversational turn. The first returns immediately, so the user actually receives the link even if your harness only delivers a turn's final message: ```bash npx --yes busabase-cli@latest login --no-wait --output json --base-url https://busabase.com ``` It returns `verification_url`, `user_code` and `resume_code` right away, and writes no credential yet. Show `verification_url` to the user exactly as returned β€” it is an opaque string, so never re-encode, trim, or re-wrap it β€” then **end your turn** so they can approve it on any device. To let them approve from a phone, render it as a QR code with `npx --yes busabase-cli@latest qrcode "" --out-file qr.png` and include the image in your reply. After the user confirms they approved, finish the sign-in in a later turn: ```bash npx --yes busabase-cli@latest login --resume-code --output json --base-url https://busabase.com --space-id YOUR_SPACE_ID ``` Continue from its safe summary: selected Space, `availableSpaces`, `createdSpace` and `bootstrapRequired`. Never ask the user to paste a secret, print `~/.busabase/.env`, or start a second login while one is pending β€” a fresh login invalidates the link the user is about to approve. If `resume_code` has expired or authorization failed, explain what happened; if the user still wants to continue, start over from the `--no-wait` command above once. The dashboard supplied `--space-id YOUR_SPACE_ID` β€” lock it as the target: never create or switch Spaces, and never ask the user to pick one. Preselection only fixes *which* Space; it does not decide whether that Space needs initializing, so read `bootstrapRequired` below regardless. Branch on the summary's `bootstrapRequired` alone, never on whether a Space happens to be empty: - **`bootstrapRequired: false`** β†’ existing user/Space, including a preselected empty Space with no bootstrap marker. Connect only and jump to Step 3 with zero structure or record writes. - **`bootstrapRequired: true`** β†’ the selected Space was auto-created for this user and still carries the persistent version-0 bootstrap marker. Ask the Step 1 scenario question, then initialize this Space even when the dashboard preselected it. Two edge cases fall out of that same rule: an empty *existing* Space has no marker and is therefore connect-only, not a trigger to initialize; and a retry after interrupted initialization still has the version-0 marker and safely resumes Step 2. On MCP, resolve the target Space from the verification result: it must match `YOUR_SPACE_ID`. Then follow `bootstrapRequired`: `false` goes to Step 3 with no writes; `true` goes to Step 1. Before the first write, require write access plus capabilities to inspect, propose, read back, and complete bootstrap. If anything is missing, stop before writing; ask the user to reconnect with more access or approve CLI fallback. Keep the same transport for the rest of the run. ## Step 1 β€” Choose a starter only for a new Space Enter this step when Cloud Step 0 returned `bootstrapRequired: true` (including a dashboard- preselected Space), or when Personal Desktop Step 0 returned an empty Base list. Ask one low-cost question. If the user says "just go ahead", use Knowledge Base. Existing users never see this question and receive zero data writes: | # | Blueprint | Good for | | - | --------- | -------- | | 1 | **Content Pipeline** (+ CMS Pages) | drafting blog / social / landing-page content reviewed before publish | | 2 | **Compliance Checklists** | controlled items where every change needs an audit trail | | 3 | **Knowledge Base** | notes, FAQs, and sources an agent can read but only a human can change | | 4 | **CRM Contacts** | leads / customers an agent enriches, with a history you can audit | | 5 | **Something else** | describe it β€” design a blueprint on the spot (see *Custom blueprint*) | A blueprint is just a starting **Base** (a table of typed fields). Available field types: `text`, `longtext`, `markdown`, `html`, `number`, `date`, `checkbox`, `select`, `multiselect`, `url`, `embed`, `email`, `phone`, `attachment`, `code`, `json`, `yaml`, `relation`, plus system types (`auto_number`, `created_time`, `ai_summary`, `ai_tags`, …). ### Blueprint field maps - **1 Β· Content Pipeline** (`content-pipeline`): `title` (text, required), `brief` (markdown), `channel` (select: blog/youtube/social), `status` (select: idea/draft/ready), `seo_title` (text), `asset` (attachment). Pair it with a CMS **Pages** base (`pages`) for AI-written HTML: `slug` (text, required), `title` (text, required), `meta_description` (text), `category` (select), `locale` (select: en/zh-CN), `html_body` (**html**, required), `status` (select: draft/in-review/live). The AI writes the HTML; the `status` field is what says it is live. - **2 Β· Compliance Checklists** (`compliance-checklists`): `item` (text, required), `owner` (email), `due_date` (date), `evidence` (attachment), `status` (select: missing/review/ complete), `notes` (longtext). - **3 Β· Knowledge Base** (`private-knowledge`): `title` (text, required), `body` (markdown), `source_url` (url), `sensitivity` (select: private/team/public), `tags` (multiselect), `attachments` (attachment). - **4 Β· CRM Contacts** (`crm-contacts`): `name` (text, required), `company` (text), `email` (email), `stage` (select: lead/qualified/customer/churned), `notes` (longtext), `last_touch` (date). ## Step 2 β€” Initialize automatically and idempotently This is the everyday write loop, not an exception to it: the user has write access to their own new Space, so structure and sample rows land immediately. They already chose this starter β€” do not ask them to approve it, and do not force a review by passing `autoMerge: false`. Every write carries system provenance and stable identity so retries cannot duplicate data. **MCP path:** skip the shell examples and have the Harness run the same sequence: inspect, create missing structure/views, seed with stable idempotency keys, read back, then complete bootstrap. Require merged structure/records and `materialized: true` views; otherwise stop for approval and resume only after a canonical View read confirms materialization. The shell examples below are for CLI only. Briefly show what is being built: ```txt πŸ“ CRM └── πŸ“Š Contacts nameΒ· companyΒ· emailΒ· stage(leadβ†’customer)Β· notesΒ· last_touch └─ relates to ─► πŸ“Š Companies nameΒ· domainΒ· tierΒ· owner ``` Build folder-first so the user never lands in a flat root full of tables: - Folder / node-tree edits use an audited Node ChangeRequest with `"autoMerge": true`. One CR can hold MANY operations β€” a create op can declare a temp `ref` that a later op targets via `parentNodeRef`, so **you can create the folder AND the Bases/Docs inside it in a single CR** (no need to merge the folder first to learn its id). - `POST /api/v1/bases` carries `"autoMerge": true`; its stable slug makes retries idempotent. Pass `parentNodeId` when placing the Base under an already-merged folder (omit it for a root-level Base node). Worked example for blueprint #1: First list nodes and Bases. Skip any stable slug already present; create only missing pieces. ```bash curl -X POST "$BUSABASE_BASE_URL/api/v1/nodes/change-requests" \ -H "Authorization: Bearer $BUSABASE_API_KEY" \ -H "x-busabase-space: $BUSABASE_SPACE_ID" \ -H 'content-type: application/json' \ --data '{ "message": "Create Content workspace folder", "autoMerge": true, "operations": [ { "kind": "create", "nodeType": "folder", "slug": "content", "name": "Content" } ], "submittedBy": "system-onboarding" }' # Read back the folder node id and use it as parentNodeId below. ``` ```bash curl -X POST "$BUSABASE_BASE_URL/api/v1/bases" \ -H "Authorization: Bearer $BUSABASE_API_KEY" \ -H "x-busabase-space: $BUSABASE_SPACE_ID" \ -H 'content-type: application/json' \ --data '{ "slug": "content-pipeline", "name": "Content Pipeline", "description": "Briefs, drafts, and SEO metadata reviewed before publishing.", "parentNodeId": "", "autoMerge": true, "fields": [ { "slug": "title", "name": "Title", "type": "text", "required": true }, { "slug": "brief", "name": "Brief", "type": "markdown" }, { "slug": "channel", "name": "Channel", "type": "select", "options": { "choices": [ { "id": "blog", "name": "Blog", "color": "slate" }, { "id": "youtube", "name": "YouTube", "color": "rose" }, { "id": "social", "name": "Social", "color": "violet" } ] } }, { "slug": "status", "name": "Status", "type": "select", "options": { "choices": [ { "id": "idea", "name": "Idea", "color": "slate" }, { "id": "draft", "name": "Draft", "color": "amber" }, { "id": "ready", "name": "Ready", "color": "emerald" } ] } }, { "slug": "seo_title", "name": "SEO Title", "type": "text" } ] }' ``` The response carries the new Base's `id` (e.g. `bse_...`) β€” use it below. For an HTML CMS, create a **Pages** base the same way with an `html_body` field of `"type": "html"`. Views are structure too, so they carry `"autoMerge": true` like everything above β€” a starter Base whose views are stuck in the review queue looks half-built to the user: ```bash curl -X POST "$BUSABASE_BASE_URL/api/v1/views/change-requests" \ -H "Authorization: Bearer $BUSABASE_API_KEY" \ -H "x-busabase-space: $BUSABASE_SPACE_ID" \ -H 'content-type: application/json' \ --data '{ "operation": "create", "baseId": "", "name": "Ready to publish", "type": "table", "autoMerge": true, "config": { "filters": [{ "fieldSlug": "status", "operator": "equals", "value": "ready" }], "sorts": [] } }' ``` > **Always leave the workspace with more than one node.** A brand-new space holding a single empty > Base renders as an empty screen β€” there's nothing for the user to see. So before seeding, give it > structure: create a containing **folder** node and put the Base inside it, or create a second related Base > (e.g. CRM Contacts **+** Companies, or Content Pipeline **+** Pages). Combined with the seeded + > merged record in 3c, the user opens a populated tree, never a blank one. Once created, point the user to the live **Graph View** (open `$BUSABASE_BASE_URL/dashboard` β†’ *Graph View* in the sidebar) so they can see the real starter structure. **3b. Seed 3–5 canonical sample records without review prompts.** Use one record call per sample because the single-record endpoint supports both `autoMerge` and `idempotencyKey`; the bulk endpoint does not auto-merge. Use a short human-readable PRIMARY field and stable versioned keys: ```bash curl -X POST "$BUSABASE_BASE_URL/api/v1/bases//change-requests" \ -H "Authorization: Bearer $BUSABASE_API_KEY" \ -H "x-busabase-space: $BUSABASE_SPACE_ID" \ -H 'content-type: application/json' \ --data '{ "fields": { "title": "Launch announcement blog post", "brief": "What changed and why it matters to existing users.", "channel": "blog", "status": "draft" }, "message": "Initialize starter content draft", "submittedBy": "system-onboarding", "idempotencyKey": "system-onboarding:v1:content:launch-announcement", "autoMerge": true }' ``` (Every call carries `x-busabase-space: $BUSABASE_SPACE_ID` β€” the space picked in Step 0. The API key is user-scoped, so do not omit the header.) Repeat with distinct stable keys for the other sample rows. The endpoint records the audited ChangeRequest and merges it immediately, leaving no `in_review` onboarding items. **3c. Read back canonical data, then mark bootstrap complete.** Never mark completion before all expected nodes, Bases, and records have been read back successfully: ```bash curl "$BUSABASE_BASE_URL/api/v1/records" \ -H "Authorization: Bearer $BUSABASE_API_KEY" \ -H "x-busabase-space: $BUSABASE_SPACE_ID" curl -X POST "$BUSABASE_BASE_URL/api/v1/onboarding/bootstrap-complete" \ -H "Authorization: Bearer $BUSABASE_API_KEY" \ -H "x-busabase-space: $BUSABASE_SPACE_ID" ``` The completion call is idempotent and changes `agentBootstrapVersion` from 0 to 1 while preserving the rest of the Space onboarding state. Recheck through the active transport; `bootstrapRequired` must now be false. ### Custom blueprint (any scenario β€” this is what keeps it general) If the user picks *Something else*, don't hunt for a matching template β€” **design one**: 1. Ask what they manage and the few attributes that matter. 2. Build a Base with **4–6 fields**, choosing types from the list above (`select` for fixed choices, `markdown`/`html` for bodies, `attachment` for files, `embed` for YouTube/Google Drive previews, `email`/`url`/`date` for typed values), following the same shape as the starter blueprints. 3. Run the same idempotent **structure β†’ sample records β†’ read-back β†’ mark complete** sequence. The starter blueprints are only calibrated examples β€” the real capability is that you can model *whatever the user actually has*. Later changes work exactly the same way: submit them, let the user's permissions decide whether they land or wait, and never approve something that is waiting. ## Step 3 β€” The last setup step: install the permanent skills Have the Harness install both skills into its persistent skill store. Prefer its native installer; otherwise run: ```bash npx skills add busabase/skills --skill busabase busabase-app-creator ``` MCP remains the transport when it connected successfully; installing skills does not require CLI credentials. Finish only after both skills are available in future sessions. This onboarding doc has now done its job. ## πŸŽ‰ You're set up β€” congratulations! **Now, and only now, is everything done β€” so this is the moment to congratulate the user, warmly and in their language.** Don't claim "you're connected / all set" before this point: it's true only once *all* of it has landed β€” - βœ… **connected** β€” the host responds (you proved it in Step 0) - βœ… **workspace ready** β€” existing Spaces were left untouched; a new Space was initialized once - βœ… **skills installed** β€” `busabase` and `busabase-app-creator` are permanent, so everyday workspace work and app creation are available in future sessions Tell them so, and close the journey with the tracker fully checked β€” e.g.: > βœ… Connect Β· βœ… Initialize (new Spaces only) Β· βœ… Verify Β· βœ… Skills > πŸŽ‰ *You're all set β€” Busabase is connected, your first workspace is live, and both skills are > installed. > From here it's everyday use: you ask, I write, and every change keeps a message, an > author and a history you can undo β€” and I can build a complete workspace app when you need one.* Finish the congratulations with a clickable Markdown link labeled **Open Busabase Dashboard**. Step 0 locked the Space ID used below; verify whichever path you connected through confirmed that same Space before replying. Never show `$BUSABASE_SPACE_ID`, `{space_id}`, `YOUR_SPACE_ID`, or any other placeholder literally to the user. The user's final line must be: > πŸ”— [Open Busabase Dashboard](https://busabase.com/dashboard/YOUR_SPACE_ID/home) Later writes omit `autoMerge`: merged where the user can write, reviewed elsewhere. Only the onboarding initializer passes `autoMerge: true`, for starter data.