atune 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +114 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# atune
|
|
2
|
+
|
|
3
|
+
Customer-understanding infrastructure for B2B SaaS. Install it like any dependency; understanding comes back through a queryable API — no dashboard to babysit.
|
|
4
|
+
|
|
5
|
+
`atune` auto-captures how your customers use your product, takes the identity you choose to send, and lets you ask grounded, cited questions about any account, user, or feature.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
const answer = await understand("account:acme", "why did they go quiet?");
|
|
9
|
+
// { knows: true, answer: "Acme's weekly active seats fell from 8 to 2…",
|
|
10
|
+
// confidence: 0.72, citations: [...], recommendedNext: "…", signals: {…} }
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
One command wires a live app — detects your framework and auth, installs the package, patches your middleware, and writes your env keys:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx atune init
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
You paste your workspace API key (from your Atune onboarding) when prompted. That's it — behavior capture starts immediately.
|
|
22
|
+
|
|
23
|
+
## Requirements
|
|
24
|
+
|
|
25
|
+
- Node 18+
|
|
26
|
+
- Next.js 14+ for the zero-config `init` (optional peer dependency). Other frameworks: use the manual setup below.
|
|
27
|
+
|
|
28
|
+
## Environment
|
|
29
|
+
|
|
30
|
+
`init` writes these to `.env.local`:
|
|
31
|
+
|
|
32
|
+
| Variable | What |
|
|
33
|
+
|----------|------|
|
|
34
|
+
| `ATUNE_API_KEY` | Your workspace key. The only secret. Server-side only — never ship it to the browser. |
|
|
35
|
+
| `ATUNE_URL` | Your Atune host. Defaults to `https://useatune.com`. |
|
|
36
|
+
|
|
37
|
+
## What gets captured
|
|
38
|
+
|
|
39
|
+
- **Behavior** is captured automatically: the middleware records every server request as `http.<method>.<normalized-route>` with the resolved account/user. Fire-and-forget — it can never block or break a request. Request bodies are **never** read (no passwords, tokens, or card numbers).
|
|
40
|
+
- **Identity** is only what you send explicitly, via `identify()` / `group()`. Personal data (name, email, company) requires an accepted data-processing agreement.
|
|
41
|
+
|
|
42
|
+
## Manual setup
|
|
43
|
+
|
|
44
|
+
If you don't want auto-wiring (or aren't on Next.js), add the middleware yourself:
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
// middleware.ts
|
|
48
|
+
import { createAtuneMiddleware } from "atune";
|
|
49
|
+
|
|
50
|
+
const atune = createAtuneMiddleware();
|
|
51
|
+
|
|
52
|
+
export function middleware(request: Request) {
|
|
53
|
+
return atune(request);
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Chain it with an existing middleware (e.g. Clerk) by calling `atune(request)` inside your handler — `init` does this for you automatically.
|
|
58
|
+
|
|
59
|
+
## Identify who is who
|
|
60
|
+
|
|
61
|
+
```ts
|
|
62
|
+
import { identify, group } from "atune";
|
|
63
|
+
|
|
64
|
+
await identify(userId, { name: "Kari Nordmann", email: "kari@acme.no" });
|
|
65
|
+
await group(accountId, { company: "Acme AS" });
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
So answers read "Kari at Acme", not "user u_123". Gated behind your accepted DPA.
|
|
69
|
+
|
|
70
|
+
## Ask: `understand()`
|
|
71
|
+
|
|
72
|
+
```ts
|
|
73
|
+
import { understand } from "atune";
|
|
74
|
+
|
|
75
|
+
const result = await understand(entity, question);
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
`entity` is one of:
|
|
79
|
+
|
|
80
|
+
| Entity | Example |
|
|
81
|
+
|--------|---------|
|
|
82
|
+
| `account:<externalId>` | `account:acme` |
|
|
83
|
+
| `user:<accountExternalId>/<userExternalId>` | `user:acme/u_123` |
|
|
84
|
+
| `feature:<key>` | `feature:feature.report` |
|
|
85
|
+
| `portfolio` | your whole book of business |
|
|
86
|
+
|
|
87
|
+
Every answer is grounded in that workspace's real signals and **cited** — and says `knows: false` when there isn't enough understanding yet, instead of guessing.
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
type UnderstandResult = {
|
|
91
|
+
knows: boolean; // false ⇒ "not enough understanding yet"
|
|
92
|
+
answer: string; // plain-language, grounded in your signals
|
|
93
|
+
confidence: number; // 0..1
|
|
94
|
+
citations: { signal: string; value: string; when: string }[];
|
|
95
|
+
recommendedNext: string | null; // one action, only when confident
|
|
96
|
+
signals: Record<string, unknown>; // the structured grounding bundle (LLM-free)
|
|
97
|
+
};
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Options: `understand(entity, question, { apiKey, url, fetch })` — all optional; `apiKey`/`url` fall back to the env vars.
|
|
101
|
+
|
|
102
|
+
## Ask from an AI agent (MCP)
|
|
103
|
+
|
|
104
|
+
Expose `understand()` to an AI coding agent or assistant over the Model Context Protocol:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
npx atune mcp
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
A stdio MCP server with a single `understand` tool. Point your agent at it and it can ask about any account, user, feature, or your portfolio on your behalf.
|
|
111
|
+
|
|
112
|
+
## Privacy
|
|
113
|
+
|
|
114
|
+
Atune is a data processor; you are the controller. Behavior is captured broadly; personal data flows only through `identify()`/`group()` under an accepted DPA. Data stays in the EU.
|