Workspace
ws_<alphanumeric> Your team boundary. Manager creates it in the cloud dashboard. All devices in a workspace contribute to the same dashboard.
Budi's cloud sync is optional. When you turn it on, only pre-aggregated numbers leave your machine — never prompts, code, or AI responses. This page is the full technical contract. For the short version, see the landing page summary.
Last updated: 2026-05-15
Your code is yours
Prompts, AI responses, source code, and file paths never leave your machine. There is no "full upload" mode — this is enforced structurally, not by a setting.
Only numbers travel
If you opt in to cloud sync, only pre-aggregated daily totals travel: token counts, cost, model name, hashed repo ID, and branch name. Nothing content-bearing.
Off by default
Cloud sync is disabled until you explicitly run budi cloud join. No telemetry, no phone-home, no automatic opt-in.
Section 1
The sync worker can only read from rollup tables — pre-aggregated counts and costs. It has no access to message content, file paths, or raw payloads. This is a structural guarantee, not a config toggle.
Your prompts
Everything you type to an AI agent stays on your machine.
AI responses
Generated code, reasoning, and tool call output stay local.
Source code & file paths
Your project structure and file system layout are never exposed.
Email addresses
Identity is handled by API key, not personal information.
Raw request/response payloads
Unstructured data dumps could contain anything sensitive.
MCP tool details
Server names, tool arguments, and execution results stay private.
Custom tag values
Tags are user-defined and could contain anything, so they stay local-only.
These are the only fields that cross the wire — all derived from pre-aggregated daily rollups. No content, no paths, no PII.
Repo identifier note: The repo_id is a SHA-256 hash of the repo root path, computed locally. The actual file system path never appears in the sync payload.
Section 2
The daemon pushes daily rollup records to the cloud — once per sync tick (every 5 minutes by default). Daily granularity gives managers the views they need without revealing per-hour work patterns.
Every push is wrapped in an envelope that identifies the device and workspace:
{
"schema_version": 2,
"device_id": "d_abc123def456",
"workspace_id": "ws_xyz789",
"label": "ivan-mbp",
"synced_at": "2026-04-10T18:30:00Z",
"payload": {
"daily_rollups": [ ... ],
"session_summaries": [ ... ]
}
} One record per unique combination of day, role, provider, model, repo, and branch. This is what a single row looks like:
{
"bucket_day": "2026-04-10",
"role": "assistant",
"provider": "anthropic",
"model": "claude-sonnet-4-20250514",
"repo_id": "sha256:a1b2c3d4e5f6",
"git_branch": "feature/PROJ-1234-add-auth",
"ticket": "PROJ-1234",
"ticket_source": "branch",
"message_count": 47,
"input_tokens": 125000,
"output_tokens": 89000,
"cache_creation_tokens": 15000,
"cache_read_tokens": 42000,
"cost_cents": 3.42
} A scrubbed per-session summary with computed totals only — no per-message detail, no paths, no content:
{
"session_id": "d99dfe22-d05c-4c78-8698-015d06e5dabb",
"provider": "claude_code",
"title": "Verkada-Web",
"started_at": "2026-04-10T09:15:00Z",
"ended_at": "2026-04-10T10:45:00Z",
"duration_ms": 5400000,
"repo_id": "sha256:a1b2c3d4e5f6",
"git_branch": "feature/PROJ-1234-add-auth",
"ticket": "PROJ-1234",
"message_count": 47,
"total_input_tokens": 125000,
"total_output_tokens": 89000,
"total_cost_cents": 3.42,
"primary_model": "claude-sonnet-4-20250514"
} Section 3
Three entities form a simple hierarchy. A workspace is your team's billing and visibility boundary. Users belong to one workspace. Each user can have multiple devices (laptop, desktop, CI runner).
Workspace (1) ──< User (many) ──< Device (many) ws_<alphanumeric> Your team boundary. Manager creates it in the cloud dashboard. All devices in a workspace contribute to the same dashboard.
usr_<alphanumeric> A cloud account created via self-registration or manager invite. Can be a member (sync data, see own stats) or manager (see everyone's stats).
dev_<alphanumeric> One budi installation on one machine. Generated locally on first login. Persists across daemon restarts — regenerated only if the config file is deleted.
Section 4
All communication is encrypted, one-directional, and initiated by your machine. The cloud never calls back to the daemon — there is no webhook, no pull endpoint, no remote command channel.
Authorization: Bearer budi_<key> header.
~/.config/budi/cloud.toml, file permissions 0600.
Besides cloud sync, the daemon can make two additional HTTPS requests for pricing data. Both
are opt-out via BUDI_PRICING_REFRESH=0:
LiteLLM pricing manifest
Anonymous GET to fetch the latest model prices. No user content, no identifiers.
Team pricing pull
Authenticated GET to fetch your workspace's negotiated price list. No user content in the request.
Section 5
Network failures, retries, and overlapping sync windows are handled gracefully. The server uses UPSERT semantics — re-sending the same data never creates duplicates.
Each record type has a unique key. If the same key arrives twice, the server overwrites the old row — so the daemon can safely retry on any failure.
(device_id, bucket_day, role, provider, model, repo_id, git_branch) (device_id, session_id) The daemon remembers the last day that was fully synced. On each tick it sends:
The server confirms the watermark in its response. If the push fails, the watermark doesn't advance — and the next tick retries.
Section 6
The current cloud alpha is designed for small teams of 1 to 20 developers.
| Aspect | How it works |
|---|---|
| Getting started | Manager signs up, creates a workspace, and shares an invite link. |
| Joining a team | Developer runs budi cloud join <invite-token> — one command. |
| Roles | Manager sees the whole team's dashboard. Member sees only their own data. |
| Data granularity | Daily cost breakdowns. No per-hour or real-time views yet. |
| Retention | 90 days of synced data. Configurable in future versions. |
| Multi-workspace | Not yet — a user belongs to exactly one workspace in v1. |
| SSO / SAML | Not yet — API key auth only. Enterprise auth is planned for post-8.0. |
Section 7
The daemon talks to exactly four cloud endpoints. The dashboard and user management APIs are separate and not covered here.
| Endpoint | What it does |
|---|---|
POST /v1/ingest | Receives the sync payload from the daemon |
GET /v1/ingest/status | Returns sync health and current watermark for the device |
GET /v1/whoami | Returns the identity of the authenticated device |
GET /v1/pricing/active | Returns the workspace's negotiated price list |
200 OK
Payload accepted. Watermark updated.
401
Auth failed. Daemon stops syncing until re-authenticated.
422
Schema mismatch. Daemon logs a warning and waits for update.
429 / 5xx
Rate limit or server error. Daemon retries with exponential backoff.
Section 8
Everything lives in one file: ~/.config/budi/cloud.toml. It's created by budi cloud join
and disabled by default — no automatic opt-in, no telemetry, no phone-home.
[cloud]
enabled = false # nothing syncs until you flip this
api_key = "budi_..." # your bearer token
device_id = "dev_..." # stable machine identifier
workspace_id = "ws_..." # your team's workspace
endpoint = "https://app.getbudi.dev" # cloud ingest URL
[cloud.sync]
interval_seconds = 300 # push every 5 minutes
retry_max_seconds = 300 # max backoff cap These override the config file — useful for CI or self-hosted deployments:
BUDI_CLOUD_ENABLED Override the enabled flag (true / false)
BUDI_CLOUD_API_KEY Override API key (useful for CI)
BUDI_CLOUD_ENDPOINT Override cloud URL (useful for self-hosted)
BUDI_PRICING_REFRESH Set to 0 to disable pricing refresh requests
Section 9
Privacy-first comes with real costs. Here's what the design intentionally gives up.
The cloud dashboard shows daily cost breakdowns. You can't drill into hourly or per-request data in the cloud — but you can locally via the CLI.
The cloud sees "47 messages cost $3.42 on this branch today" — never the content of those messages. Less debuggable, more private.
Custom tags stay local-only because their values are user-defined and could contain anything sensitive. Managers filter by model/repo/branch/ticket instead.
If you consult for multiple clients, you can't aggregate across workspaces yet. Multi-workspace is planned for post-8.0.
No SSO, SAML, or OAuth yet. Fine for small-team alpha; enterprise auth is on the roadmap.
Managers can't push budget limits or settings to developer machines. All config is local. Budget enforcement happens on your machine, not in the cloud.
Section 10
Changes to the original data contract since it was published. In every case, the core privacy guarantee — no content, no code, no prompts leave your machine — is unchanged.
The daemon now fetches an open-source pricing manifest (LiteLLM) to stay current with
model costs. This is an anonymous request with no user data attached. Disable with BUDI_PRICING_REFRESH=0.
Workspaces can now set custom model prices. The daemon fetches these via an authenticated request that carries no user content — just a small JSON of rates. Same opt-out switch.
"Organization" was renamed to "Workspace" across the codebase. The daemon accepts both the
old
org_id and new workspace_id
keys during a transition period so existing configs keep working without edits.
Questions about the data contract? Open an issue or check the wiki source.