Overview
Busa CRM is a Busabase Cloud App-in-Skill. Its canonical product surface is the
AirApp in Busabase, not a separate local-data product. The same Hono source
supports an explicitly requested local preview with OAuth connection bootstrap.
It keeps a Busabase-backed dashboard over contacts, companies, deals, and
interactions, plus a review queue of agent-drafted follow-up messages. The
skill gathers and updates CRM data from whatever the operator feeds it — emails,
meeting notes, chat asks — drafts follow-ups, and hands off an approved
follow-up to another channel skill (for example busa-email) only after
explicit approval.
Default behavior is AirApp-first. Unless the user explicitly asks only for
explanation, update Busabase directly and give the user the clickable AirApp
URL. Start localhost only when local preview/debugging is explicitly
requested; it uses the same Busabase resources and never offers another data
provider. Use chat-only mode only when the user says "纯聊天", "chat only",
"不要打开 UI", or similar; in that mode present numbered follow-ups
(Follow-up #1) and take verdicts in the conversation, still writing them
through Busabase.
Mandatory Dependencies
- Read and follow
$kelly-app-skill-creatorfor product behavior, visual quality, responsive layout, and the complete canonicalcontent/busa-crm-app/artifact. - Read and follow
$busabasefor connection, target Space, node discovery, ChangeRequests, review, and merge behavior. - Read and follow
$busabase-app-creatorfor resource modeling, AirApp runtime limits, security, validation, and deployment.
If a dependency is unavailable, preserve this skill's local artifact and product contracts, stop before the unavailable Busabase operation, and report the exact missing dependency. Do not invent a second data backend.
App UI Screenshots
Boundary
- The AirApp reads Busabase records, drafts follow-up messages, and records human decisions only through Busabase writes. It must never send emails or messages, call external APIs, or perform any external side effect.
- Outbound follow-up messages are always approval-required. Sending is
delegated to other skills (for example
busa-email) and happens only after the user approves the specific follow-up.scripts/execute_decisions.mjsonly marks an approved followupdonewith handoff metadata; it performs no sending itself. - Treat all contact and deal data as sensitive. Never commit real contact details, tokens, or Busabase credentials.
Busabase Resources
Six Bases under one application Folder (busa-crm), declared in
content/busa-crm-app/app/js/config.js and the generated template sidecars under content/:
companies: name, domain, industry, size, location, notes.contacts: name, company, role, email, relationship strength, tags, last touch, next follow-up, agent notes, channels.deals: name, company, primary/linked contacts, stage, amount, currency, probability, next step, owner, dates, status, agent-suggested next action.interactions: contact, company, deal, type, direction, summary, source.followups: the review queue — contact, deal, channel, reason, risk badges, due date, workflowstatus, editablesuggested_reply, and the human verdict fieldsdecision_comment/decided_at/decided_bywritten directly onto the record (there is no separate decisions file).settings: operator profile, pipeline stages, channels, and the agent lock, one row perkind.
Resources provision lazily through an idempotent Busabase ChangeRequest the
first time the app runs in a Space; see references/crm-schema.md for exact
field shapes.
Authentication
Busabase authentication is ambient inside the deployed AirApp, which must not
show OAuth, API-key, Base URL, provider, hosting, or Space controls.
Standalone loopback preview uses browser OAuth without exposing tokens; after
OAuth it auto-selects a single/open-source Space or requires a native
selector when several Spaces are accessible. It performs no app-resource read
or initialization before selection. scripts/execute_decisions.mjs (a
trusted process, not the AirApp) uses BUSABASE_BASE_URL /
BUSABASE_API_KEY / BUSABASE_SPACE_ID from the environment.
Review Workflow
Follow-ups use the standard workflow states: needs_review,
changes_requested, approved, done, blocked. A human verdict
(approve / request_changes / block / revise) writes the new status
plus decision_comment / decided_at / decided_by directly onto the
followup record through busabase-sdk. From a standalone local preview the
write merges immediately (trusted operator); from the deployed AirApp it
creates a pending ChangeRequest for the trusted process to merge, per the
AirApp boundary in $busabase-app-creator.
- When the operator feeds new material (emails, meeting notes, chat asks): upsert
companies/contacts/deals by stable domain id (
company_id,contact_id,deal_id), append interactions, and draft new followups withstatus: "needs_review", a clearreason, risk badges, and asuggested_replydraft — all as Busabase writes. - Give the operator the AirApp URL (or local preview URL) to review the pipeline and the follow-up queue.
- For a followup moved to
changes_requested, re-draft it per the review comment and write it back toneeds_review. - On "execute" / "send approved follow-ups": run
node scripts/execute_decisions.mjs --applyto re-read approved followups from Busabase and mark themdonewith handoff metadata, then perform the actual send only through the corresponding skill (for example$busa-email) with the approved, possibly user-edited draft, one follow-up at a time. - Never send anything for a followup without an explicit
approvedecision, and never re-send a followup alreadydone.
Demo Mode
?demo=1 opens a deterministic, read-only mock CRM for documentation and
screenshots (content/busa-crm-app/app/js/providers/demo-provider.js). ?demo=overview,
?demo=deals, ?demo=contacts, ?demo=followups, and ?demo=detail select
named mock scenes; detail deep-links to a deal detail. lang=en or
lang=zh forces UI chrome language. Demo mode never reads or writes
Busabase and never claims a real connection.
Completion Criteria
Finish only when:
- the skill contains the complete canonical
content/busa-crm-app/project andpnpm --dir content/busa-crm-app devremains supported; - all persistent config, state, decisions, and domain data use
busabase-sdkand the declared resource map — no local JSON, browser storage, or provider choice; - Vault values and API credentials never reach browser-visible surfaces;
- local setup offers Cloud/custom URL OAuth plus the explicit Demo path, while a deployed AirApp uses its ambient session;
- Overview, Deals, Contacts, Follow-ups, and Help & Settings render on desktop and phone widths;
pnpm --dir content/busa-crm-app run checkandnode --testpass.
Stop Conditions
Stop before consequential Busabase mutation when the target Space is ambiguous, the current user lacks permission, or a same-slug resource is not application-owned. Never send, publish, or otherwise mutate an external system directly from the AirApp.