Tuturuuu SDK
Official TypeScript/JavaScript SDK for interacting with the Tuturuuu platform. Provides type-safe access to workspace storage, files, documents, and agent-friendly task workflows.Installation
Quick Start
Features
Bun CLI
Use
ttr for browser login, workspace discovery, and task workflowsHeadless Login
Copy a short-lived CLI token from the browser when a local callback is not
available
Storage Operations
Upload, download, list, and delete files and folders
Document Management
Create, read, update, and delete workspace documents
Signed URLs
Generate temporary shareable links for files
Image Resizing
Apply Supabase image transformations during share and download
Analytics
Track storage usage, file counts, and limits
CLI
The SDK package includes a native Bun-powered CLI.ttr is the primary command,
and tuturuuu plus tutur3u are aliases for the same binary.
ttr login opens the browser and creates a Tuturuuu-managed CLI app-session
JWT pair through apps/web. The terminal and browser confirmation page show the
signed-in account email when the web session exposes it. The CLI stores that
session and selected workspace, board, list, task, label, and project in the OS
app config directory. personal is the default workspace after login and when
no workspace has been selected:
Use ttr host use to switch between Tuturuuu origins. production and prod
resolve to https://tuturuuu.com; local and localhost prefer safe local
environment URLs from TUTURUUU_LOCAL_BASE_URL, PORTLESS_URL, WEB_APP_URL,
NEXT_PUBLIC_WEB_APP_URL, or NEXT_PUBLIC_APP_URL, then fall back to
https://tuturuuu.localhost. Pass --port <port> for
http://localhost:<port>, or --portless --port <port> for
https://tuturuuu.localhost:<port>. Changing origins clears the saved session
and selected workspace context because both are origin-specific.
ttr config set-base-url <url> remains available for compatibility and uses the
same host normalization and context-clearing behavior. The CLI normalizes
0.0.0.0 and unspecified IPv6 origins to localhost so the browser login flow
does not open a blocked address.
On Dockerized production deployments, the web auth start route also rewrites
wildcard bind origins such as 0.0.0.0:7803 to the forwarded public host or the
configured app URL (WEB_APP_URL, NEXT_PUBLIC_WEB_APP_URL,
NEXT_PUBLIC_APP_URL, COOLIFY_URL, or COOLIFY_FQDN) before sending users to
/login. If those environment values are unset and no public forwarded host is
available, https://tuturuuu.com is the default fallback.
- macOS:
~/Library/Application Support/Tuturuuu/config.json - Linux:
$XDG_CONFIG_HOME/tuturuuu/config.jsonor~/.config/tuturuuu/config.json - Windows:
%APPDATA%\Tuturuuu\config.json
TUTURUUU_CONFIG to use a custom config
file, or use ttr host use <target> to target a local, production, or explicit
URL origin.
The CLI checks the npm registry at most once per hour and writes a notice to
stderr when a newer tuturuuu version is available. This keeps --json output
machine-readable for agents. Use ttr upgrade to run bun i -g tuturuuu. Use
--no-update-check on a single command, or set TUTURUUU_DISABLE_UPDATE_CHECK=1,
to disable the check.
CLI sessions are dedicated Tuturuuu gateway JWTs, separate from normal browser
and Supabase Auth sessions. The CLI stores a short-lived app-session access JWT
plus a longer-lived refresh JWT, refreshes shortly before access-token expiry,
updates the saved config with the rotated refresh token, and retries once after a
401 response. Refresh JWTs only carry the CLI refresh scope, so they cannot be
used directly as API bearer tokens. If refresh fails because the user no longer
exists or the refresh JWT has expired, run ttr login again.
The SDK fetch wrapper must attach CLI bearer tokens, refresh sessions, and retry
401 responses only for relative Tuturuuu API paths or absolute URLs whose
origin exactly matches the configured CLI base URL. Cross-origin absolute URLs
must be delegated without Authorization headers.
API routes used by ttr must accept the CLI app-session access JWT from the
Authorization: Bearer ... header. For apps/web routes, prefer
withSessionAuth with targetApp: 'platform' and
requiredScope: 'cli:access' when the route is CLI-only; shared user profile
routes can include the platform target alongside satellite app targets. Shared
API routes should verify the CLI app-session token before falling back to
Supabase session auth and then keep workspace membership checks explicit.
When a handler lives in packages/apis and is reused by multiple apps, keep
@tuturuuu/auth imports in the app-owned route wrapper and pass a
pre-authenticated context into the shared handler so package builds do not form
an auth/UI/API cycle.
SDK version and changelog PRs are generated by
.github/workflows/release-please.yaml from Conventional Commits on
production. Release Please tracks the SDK in release-please-config.json as
the sdk component, records the current version in
.release-please-manifest.json, and updates packages/sdk/package.json in the
combined monorepo release PR. SDK releases are then published automatically from
.github/workflows/release-sdk-package.yaml when that version bump lands on
production or when the release workflow itself changes. The same publish
workflow can be dispatched manually to catch up a version that already landed on
production. Manual dispatches from any other ref are rejected before
dependency installation, packaging, or npm trusted publishing can run. The
workflow runs the SDK tests, skips publication if the exact package version
already exists on npm, waits for publishable Tuturuuu workspace dependencies to
be visible on npm, prepares a tarball with npm pack outside the
trusted-publish job, and then publishes that tarball through
npm trusted publishing. Only the
final publish-npm job requests id-token: write, so GitHub Actions mints the
short-lived OIDC token after dependency installation, package builds, and version
checks have already finished. That job downloads the prepared artifact, verifies
its package name and version, confirms the bundled npm CLI supports trusted
publishing, runs npm publish ./<tarball> --ignore-scripts, and polls npm view
until the exact SDK version is visible without using an NPM_TOKEN. npm treats
the downloaded artifact as a local file path. The job
targets the GitHub environment sdk-release-production; keep that environment
restricted to the production branch in repository settings, and keep the npm
trusted publisher bound to the same environment name so a branch-selected
workflow cannot mint a matching npm publish identity. Do not add bun install,
npm install -g, package builds, package lifecycle scripts, or repository
secrets to the SDK release workflow. Because the tuturuuu package is public
and tutur3u/platform is a public repository, npm also generates and attaches
build provenance attestations automatically. The package manifest inside the
tarball must keep repository metadata aligned with the provenance repository:
repository.url is https://github.com/tutur3u/platform, and
repository.directory points at the package directory.
.github/workflows/sdk-version-bump.yaml is retired and no longer generates
patch-version PRs. Do not restore checksum or package-only bump automation for
the SDK; release-please must remain the version/changelog source of truth.
The SDK imports @tuturuuu/devbox, @tuturuuu/types, and
@tuturuuu/internal-api through package exports that point at their git-ignored
dist/ directories. The release workflow must build those workspace packages in
the non-OIDC build and prepare jobs before running SDK tests or creating the
npm pack tarball; otherwise a clean Actions checkout cannot resolve the SDK
imports. The workflow then runs
node scripts/ci/prepare-npm-package-manifest.js packages/sdk before
npm pack so the published manifest contains concrete npm versions instead of
local workspace: protocol ranges. Keep matching npm release workflows for the
SDK runtime workspace dependencies so consumers can install the published SDK.
When release-please bumps the SDK and one of those dependencies in the same
production push, the SDK workflow waits for the dependency versions before it
packs and publishes. If a dependency release workflow for the same SHA fails,
the SDK wait fails immediately instead of waiting for npm visibility until
timeout.
The matching npm-side trusted publisher must stay configured at
https://www.npmjs.com/package/tuturuuu/access with these exact values:
- Provider: GitHub Actions
- Organization or user:
tutur3u - Repository:
platform - Workflow filename:
release-sdk-package.yaml - Environment name:
sdk-release-production
npm publish can fail with ENEEDAUTH, E404, or
permission text. Update the npm package access or trusted publisher entry first;
do not paper over the failure by reintroducing a long-lived NPM_TOKEN. After
confirming a trusted-publisher release works end to end, the npm package
settings should keep Require two-factor authentication and disallow tokens
enabled so the package cannot be published with classic tokens.
Devbox Setup
Usettr box setup on self-hosted runner machines before offloading expensive
checks, Supabase workflows, or E2E suites. The command clones or reuses
https://github.com/tutur3u/platform.git at ~/Documents/tuturuuu, runs
bun install --frozen-lockfile, starts the local Supabase stack with
bun sb:start, reads supabase status -o json, and upserts local Supabase
connection values into ignored apps/*/.env.local files with secret values
redacted from CLI output.
ttr box doctor stays read-only. Use ttr box setup --yes only when the host
should install detected missing prerequisites through its package manager.
Use ttr box repair --dir . after a CLI upgrade to repair an existing runner
service without registering a new runner token.
Scoped Help
Use scoped help when you know the area but not the exact flags. Help commands do not require login, do not read the saved config, and do not run the update check.Agent-Friendly Discovery
For autonomous engineering workflows, start by discovering the current account and selected context:ttr whoami shows login state, account email, current workspace, selected
board/list/task/label/project ids, base URL, config path, and the Tuturuuu CLI
session label. Use --json --no-update-check when another agent is going to
parse stdout.
The v1 task surface covers workspaces, boards, lists, tasks, labels, projects,
relationships, moves, and bulk task updates. Read-oriented groups list by
default, so ttr tasks and ttr workspaces are equivalent to their explicit
list forms. ttr boards shows active, unarchived boards by default; use
ttr boards --archived, ttr boards --deleted, or ttr boards --all when an
agent needs archived or deleted board inventory. Unscoped ttr tasks starts
from the personal workspace and lists personal tasks plus open tasks assigned to
the user in other accessible workspaces; selecting a board/list or passing
--workspace scopes the result back to that context. ttr tasks shows open
tasks by default by excluding rows with completed_at or closed_at and by
limiting task-list statuses to not_started and active. That default hides
tasks in documents, review, done, and closed lists, and tasks from
archived boards; use --all, --include-archived, --documents, --review,
--done, --closed, --include-documents, --include-review,
--include-done, or --include-closed to adjust that filter. Results are
paginated at 50 tasks by default; use
--page/--page-size or --limit/--offset to page through larger task sets.
Human-readable task lists show a footer with the total task count and current
page/max page. Add --compact to task lists when an agent only needs the task
title, task list name, and per-task workspace name. Task lists are ordered by
priority and due date, with prettier due dates and configured task-list colors
in table output. Human-readable tables use smooth box borders, respect the
terminal width, and wrap long cell content so task titles stay readable instead
of overflowing narrow panes. Add --json
when another agent or script needs machine-readable output. tasks create, boards create, and lists create accept a quoted positional name as
a shorthand for --name. Task CRUD accepts either the task UUID or the board
identifier shown in the UI, such as VHP-12; prefixed identifiers resolve
within the selected workspace even when another list is selected, and matching
human-readable output keeps that prefixed identifier visible. Marking a task
completed stamps completed_at so Tuturuuu moves it to the first done list;
pass --list <done-list-id> or include list_id in --json-payload to choose
another done destination. Use ttr tasks done [task-id] as the quick shortcut.
Use ttr tasks close [task-id] to stamp closed_at; pass --list <closed-list-id> to choose a specific closed destination.
Finance CLI
Finance commands use the selected workspace and the same authenticated internal APIs as the web app. Use--workspace or --ws to target a different
workspace, and use --json-payload when a script needs to send fields that do
not have dedicated flags yet. Finance list output is paginated by default; use
--page/--page-size or --limit/--offset to move through larger result
sets.
Finance API routes that back ttr finance should resolve access through
getFinanceRouteContext from @tuturuuu/apis/finance/request-access, with
app-owned routes passing resolveFinanceRouteAuthContext(request) from
apps/web/src/lib/finance-route-auth.ts when they need CLI app-session bearer
token support. Keep CLI token verification in the app layer so @tuturuuu/apis
does not depend on @tuturuuu/auth; getFinanceRouteContext still keeps the
pre-authenticated actor, browser Supabase sessions, personal workspace
resolution, and finance permission checks on the same path.
Calendar CLI
Calendar commands use the selected workspace and the same authenticated calendar APIs as the web app. Use--workspace or --ws to target a different
workspace, and use --json when scripts need the raw structured response.
Human output renders resource-specific tables for events, calendars, categories,
accounts, provider calendars, connections, sources, and schedulable tasks.
Event time input is exact ISO datetime only. events create requires --start
and exactly one of --end or --duration-minutes; events update --duration-minutes also requires --start. Source flags map to provider
payloads: use --source-provider tuturuuu --calendar <workspace-calendar-id>
for workspace calendars, or --source-provider google|microsoft --connection <connection-id> for connected provider calendars. calendar calendars reset
is destructive and requires --yes.
use, get, update, delete, or
move commands to pick a workspace, board, list, task, label, or project with
the keyboard. The interactive picker shows one-based indexes, colored badges
such as [FREE] Tuturuuu and [PRO] Personal, task-list color swatches, the
selected row, and muted metadata. Use up/down or j/k to move, space/enter to
select, and escape/q to cancel. Interactive selection is disabled for --json
output. Picker labels, descriptions, badges, and color names derived from
platform data must visibly escape terminal control characters before rendering.
Use ttr -v or ttr --version to print the installed CLI version.
Client Initialization
Basic Usage
With Custom Configuration
Storage API
List Files
Lists files and folders in the workspace drive.Upload File
Uploads a file to the workspace drive.Download File
Downloads a file as a Blob.Delete Files
Deletes one or more files or folders.Create Folder
Creates a new folder in the workspace drive.Share File
Generates a signed URL for temporary file sharing.Get Analytics
Retrieves storage usage statistics for the workspace.Documents API
List Documents
Lists documents in the workspace with optional filters.Create Document
Creates a new document in the workspace.Get Document
Retrieves a document by its ID.Update Document
Updates an existing document.Delete Document
Deletes a document permanently.Search Documents
Searches documents by name (alias forlist() with search).
CMS Delivery
The SDK also exposes the external-project delivery client that powers Tuturuuu CMS preview surfaces and branded external apps.artworkCategories comes from the configured gallery taxonomy on singleton-sections/gallery (profile_data.categoryOptions) rather than being inferred from every artwork entry.
External app admin dashboards can auto-create and bind the workspace studio before their first diff/apply when the workspace ID is configured and the app token has external-projects:* or manage scope:
Public Folder Asset Sync
External apps can keep seed media in their localpublic/ folder and still publish it through Tuturuuu Drive. Mark each manifest asset with metadata.publicPath, metadata.localAssetPath, metadata.sourcePublicPath, or a relative sourceUrl.
external-projects/{adapter}/{collectionSlug}/{entrySlug}/{filename}. The upload helper uses the external-project asset app-server upload route so Tuturuuu measures the actual bytes before writing storage objects; production Supabase keys are not needed in external apps.
TanStack Query
For React apps, keep the SDK as the delivery boundary and TanStack Query as the cache owner:Error Handling
The SDK provides specific error classes for different scenarios:Error Properties
All error classes include:message- Human-readable error descriptioncode- Machine-readable error codestatusCode- HTTP status codename- Error class name
TypeScript Support
The SDK is fully typed with TypeScript:API Key Management
Creating an API Key
- Log in to your Tuturuuu workspace
- Navigate to Settings → API Keys
- Click “Create API Key”
- Set a descriptive name
- Assign a Workspace Role (determines permissions)
- Optionally set an expiration date
- Copy the generated key (starts with
ttr_) - Store securely (you won’t see it again)
Best Practices
Permissions
API keys inherit permissions from their assigned Workspace Role. The role determines what operations the key can perform. Required Permissions:| Operation | Required Role Permission |
|---|---|
| Storage Operations (list, upload, download, delete, folders, share, analytics) | manage_drive |
| Document Operations (list, create, get, update, delete, search) | manage_documents |
| API Key Management | manage_api_keys (Owner/Admin only) |
Security Best Practices
❌ Insecure (NEVER do this)
✅ Secure (Recommended patterns)
Next.js App Router (Recommended)
Create server-side API routes that proxy SDK calls:Node.js/Express Backend
Serverless Functions (Netlify, Vercel, AWS Lambda)
Security Checklist
✅ DO: Use server-side code
✅ DO: Use server-side code
Always use the SDK in server-side contexts:
- Next.js API Routes (App Router or Pages Router)
- Node.js backend servers
- Serverless functions
- Server Components (React Server Components)
✅ DO: Use environment variables
✅ DO: Use environment variables
Store API keys in environment variables:Never use
NEXT_PUBLIC_ prefix for API keys!✅ DO: Add .env.local to .gitignore
✅ DO: Add .env.local to .gitignore
Ensure secrets never get committed:
gitignore # .gitignore .env.local .env*.local ❌ DON'T: Use NEXT_PUBLIC_ prefix
❌ DON'T: Use NEXT_PUBLIC_ prefix
This exposes the variable to the browser:
bash # BAD - Exposed to client! NEXT_PUBLIC_TUTURUUU_API_KEY=ttr_key ❌ DON'T: Import SDK in client components
❌ DON'T: Import SDK in client components
Never import the SDK in files with
'use client' directive.❌ DON'T: Hardcode API keys
❌ DON'T: Hardcode API keys
Never commit keys to version control:
Complete Example
See the external app example for a complete implementation showcasing:- ✅ Secure server-side API routes
- ✅ File upload with progress
- ✅ Storage analytics dashboard
- ✅ Proper error handling
- ✅ Environment variable configuration
Rate Limiting
The API enforces rate limits per API key to ensure fair usage and system stability:Rate Limits by Operation
| Operation | Limit | Window |
|---|---|---|
| Storage Upload | 20 requests | per minute |
| Storage Download | 50 requests | per minute |
| Signed Upload URLs | 30 requests | per minute |
| All Other Operations | 100 requests | per minute |
Rate Limit Headers
Every API response includes rate limit information in the headers:X-RateLimit-Limit- Maximum requests allowed in the time windowX-RateLimit-Remaining- Number of requests remaining in current windowX-RateLimit-Reset- Unix timestamp when the rate limit resets
Handling Rate Limits
When you exceed the rate limit, the API returns a429 Too Many Requests response:
Workspace-Specific Rate Limits
Workspace administrators can configure custom rate limits for their workspace through Workspace Secrets. These override the default limits for all API keys in that workspace. To set custom rate limits:- Navigate to Settings → Workspace Settings → Secrets
- Add one or more of these secrets:
| Secret Name | Description | Example Value |
|---|---|---|
RATE_LIMIT_WINDOW_MS | Time window in milliseconds | 60000 (1 minute) |
RATE_LIMIT_MAX_REQUESTS | Max requests per window | 200 (double the default) |
Workspace-specific rate limits only apply to operations that don’t have
explicit per-operation limits. For operations like uploads and downloads, the
operation-specific limits still apply.
Best Practices
Examples
Basic Usage
Complete example of all SDK operations
Error Handling
Comprehensive error handling patterns
Support
GitHub
Source code and issues
Discord
Community support
Docs
Full documentation
Changelog
v0.1.0 (2025-10-21)
- Initial release
- Storage operations (list, upload, download, delete, folders, share, analytics)
- Document operations (CRUD, search)
- Comprehensive error handling
- Full TypeScript support
- Zod validation