diff --git a/.cspell.json b/.cspell.json index dc8420a..082f577 100644 --- a/.cspell.json +++ b/.cspell.json @@ -52,6 +52,7 @@ "OAuth", "OneDrive", "PayPal", + "PCCI", "PKCE", "Premai", "Reauth", @@ -61,6 +62,8 @@ "Salesforce", "SaaS", "Sentry", + "subprocessor", + "subprocessors", "Skydo", "Slack", "Slackbot", diff --git a/AGENTS.md b/AGENTS.md index 985bde2..cef0aba 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -10,8 +10,9 @@ ## Information architecture -The IA tracks the user's journey from "just landed" to "pro user". Five sidebar groups: +The IA tracks the user's journey from "just landed" to "pro user". Beta documentation sits first, followed by the core product journey, Remote access, Reference, and Release notes: +- **Agents (Beta)** - `/developers/*`. The public REST reference and a source-backed architecture overview. - **Get started** — `/introduction`, `/quickstart`, `/going-deeper`. The path from "is this for me?" through "I have it set up" to "I've made it part of my work". - **Workflows** — `/workflows/*`. Six concrete stories: morning brief, meetings, research-to-deck, content launch, bug-to-PR, knowledge recall. - **Features** — the five primitives: `/features/{chat, mcp, skills, tasks, memory}`. Everything Fluso does is some combination of these five. diff --git a/app/global.css b/app/global.css index c03c536..dce5ad6 100644 --- a/app/global.css +++ b/app/global.css @@ -66,6 +66,10 @@ html > body[data-scroll-locked] { --removed-body-scroll-bar-size: 0px !important; } +[role='dialog'] button code { + overflow-wrap: anywhere; +} + /* Release notes: each entry uses bold labels as its section headings. They are not real headings on purpose - the page holds every release, so real headings would put a hundred items in the table of contents. Give the labels the spacing and diff --git a/components/diagrams.tsx b/components/diagrams.tsx index 538c18b..2730caf 100644 --- a/components/diagrams.tsx +++ b/components/diagrams.tsx @@ -1,8 +1,14 @@ import { + Bot, Clock3, + Database, FileText, FolderClosed, MessageSquareText, + Network, + PlugZap, + Server, + ShieldCheck, Users, } from 'lucide-react'; @@ -202,3 +208,316 @@ export function KnowledgeGraphDiagram() { ); } + +const architectureServices = [ + { + label: 'Fluso client', + detail: 'Desktop or remote', + x: 10, + icon: MessageSquareText, + }, + { + label: 'Edge', + detail: 'TLS + routing', + x: 162, + icon: ShieldCheck, + }, + { + label: 'REST API', + detail: 'Identity + records', + x: 314, + icon: Server, + }, + { + label: 'Agent gateway', + detail: 'Admission + routing', + x: 466, + icon: Network, + emphasis: true, + }, + { + label: 'User runtime', + detail: 'Thread worker + tools', + x: 618, + icon: Bot, + }, +] as const; + +const architectureData = [ + { + label: 'PostgreSQL', + detail: 'Platform records', + owner: 'REST API', + x: 380, + icon: Database, + }, + { + label: 'Isolated user storage', + detail: 'Projects, sessions, Agents', + owner: 'Gateway + runtime', + x: 532, + icon: FolderClosed, + }, +] as const; + +const ARCHITECTURE_NODE_WIDTH = 132; + +function ArchitectureNode({ + label, + detail, + x, + icon: Icon, + emphasis = false, +}: { + label: string; + detail: string; + x: number; + icon: typeof FolderClosed; + emphasis?: boolean; +}) { + return ( + + + + ); +} + +export function ArchitectureDiagram() { + return ( +
+

+ Scroll horizontally to view the full diagram. +

+
+ + + Fluso request and data boundaries + + + A Fluso client sends an authenticated request through the edge, REST + API, Agent gateway, and a user runtime. The API owns platform + records. The gateway and runtime use durable workspace storage. The + runtime queries knowledge and calls governed MCP servers. + + + + + + + + + + Request path + + + + + + + + + + + + + {architectureServices.map((node) => ( + + ))} + + + + Data and context + + + + + + {architectureData.map(({ label, detail, owner, x, icon: Icon }) => ( + + + + {label} + + + {detail} + + + {owner} + + + ))} + + + + + Runtime context + + + + + Knowledge service + + + + + + MCP servers + + + + +
+ +
+ Compute, platform state, workspace data, knowledge, and external sources + meet through explicit service boundaries. +
+
+ ); +} diff --git a/components/mintlify.tsx b/components/mintlify.tsx index 6b872a7..7912e75 100644 --- a/components/mintlify.tsx +++ b/components/mintlify.tsx @@ -61,6 +61,37 @@ export function Check({ children }: { children: ReactNode }) { return {children}; } +const methodStyle = { + GET: 'bg-sky-500/10 text-sky-700 dark:text-sky-300', + POST: 'bg-emerald-500/10 text-emerald-700 dark:text-emerald-300', + PATCH: 'bg-amber-500/10 text-amber-700 dark:text-amber-300', + DELETE: 'bg-red-500/10 text-red-700 dark:text-red-300', +} as const; + +export function Endpoint({ + method, + path, +}: { + method: keyof typeof methodStyle; + path: string; +}) { + return ( +
+ + {method} + + + {path} + +
+ ); +} + // --- Cards --- export function Card({ diff --git a/content/docs/developers/agents-and-versions.mdx b/content/docs/developers/agents-and-versions.mdx new file mode 100644 index 0000000..b536039 --- /dev/null +++ b/content/docs/developers/agents-and-versions.mdx @@ -0,0 +1,209 @@ +--- +title: Agents and versions +sidebarTitle: Agents & versions +icon: bot +description: Create Agents, read their current immutable configuration, and publish safe updates. +--- + +An Agent record points at one immutable configuration through `currentConfigId`. Use that ID as `baseConfigId` when you update the Agent. + +Agent-owned work runs in [threads](/developers/threads-and-messages) and can start from [schedules](/developers/schedules). + +## List Agents + + + +Returns paginated Agent summaries, with optional text search through `q`. + +```bash title="Request" +curl "$FLUSO_API/v1/agents?page=1&limit=20&q=release" \ + -H "Authorization: Bearer $FLUSO_TOKEN" +``` + +```json title="Response: 200" +{ + "agents": [ + { + "agentId": "agt_0123456789ab4def8123456789abcdef", + "currentConfigId": "cfg_11111111111141118111111111111111", + "name": "Release reviewer", + "description": "Reviews release candidates", + "projectName": "Release Review", + "responseMode": "high", + "createdAt": "2026-08-31T09:00:00Z", + "updatedAt": "2026-08-31T09:00:00Z", + "lastChatAt": null, + "chatCount": 0, + "activeScheduleCount": 0, + "nextRunAt": null + } + ], + "pagination": { "page": 1, "limit": 20, "total": 1, "pages": 1 } +} +``` + +## Create an Agent + + + +Creates an Agent and its first immutable configuration. + +Create `Release Review` through `POST /v1/agent/projects` first. `Home` is available by default. + +```bash title="Request" +curl "$FLUSO_API/v1/agents" \ + -X POST \ + -H "Authorization: Bearer $FLUSO_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{ + "name": "Release reviewer", + "description": "Reviews release candidates", + "goal": "Return a go or no-go decision", + "instructions": "Cite blockers and name each follow-up owner.", + "conversationStarters": ["Review this candidate"], + "responseMode": "high", + "projectName": "Release Review" + }' +``` + +```json title="Response: 201, selected fields" +{ + "agentId": "agt_0123456789ab4def8123456789abcdef", + "currentConfigId": "cfg_11111111111141118111111111111111", + "state": "active", + "createdAt": "2026-08-31T09:00:00Z", + "updatedAt": "2026-08-31T09:00:00Z", + "lastChatAt": null, + "chatCount": 0, + "config": { + "schemaVersion": 1, + "configId": "cfg_11111111111141118111111111111111", + "agentId": "agt_0123456789ab4def8123456789abcdef", + "name": "Release reviewer", + "normalizedName": "release reviewer", + "description": "Reviews release candidates", + "goal": "Return a go or no-go decision", + "instructions": "Cite blockers and name each follow-up owner.", + "conversationStarters": ["Review this candidate"], + "responseMode": "high", + "threadManagementEnabled": true, + "threadCreationMode": "explicit", + "projectName": "Release Review", + "knowledgeFiles": [], + "skills": null, + "connectors": null, + "createdAt": "2026-08-31T09:00:00Z", + "contentDigest": "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" + } +} +``` + +## Read the current configuration + + + +Returns the Agent record and the configuration named by `currentConfigId`. + +```bash title="Request" +curl "$FLUSO_API/v1/agents/agt_0123456789ab4def8123456789abcdef" \ + -H "Authorization: Bearer $FLUSO_TOKEN" +``` + +```json title="Response: 200, selected fields" +{ + "agentId": "agt_0123456789ab4def8123456789abcdef", + "currentConfigId": "cfg_11111111111141118111111111111111", + "state": "active", + "config": { + "schemaVersion": 1, + "configId": "cfg_11111111111141118111111111111111", + "name": "Release reviewer", + "goal": "Return a go or no-go decision" + } +} +``` + +## Publish an update + + + +Creates a new configuration when the submitted fields change the Agent. + +```bash title="Request" +curl "$FLUSO_API/v1/agents/agt_0123456789ab4def8123456789abcdef" \ + -X PATCH \ + -H "Authorization: Bearer $FLUSO_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{ + "baseConfigId": "cfg_11111111111141118111111111111111", + "goal": "Return a go or no-go decision with named owners" + }' +``` + +```json title="Response: 200, selected fields" +{ + "agentId": "agt_0123456789ab4def8123456789abcdef", + "currentConfigId": "cfg_22222222222242228222222222222222", + "state": "active", + "config": { + "schemaVersion": 1, + "configId": "cfg_22222222222242228222222222222222", + "goal": "Return a go or no-go decision with named owners" + } +} +``` + +An unchanged patch returns the existing config ID. A stale `baseConfigId` returns `409 STALE_AGENT_CONFIG` and includes the current config ID in `error.details.currentConfigId`. + +## List available configurations + + + +Returns up to 100 available immutable configurations, newest first. Older +configurations that no chat uses may be reclaimed under storage pressure, so +this endpoint is not a permanent audit ledger. + +```bash title="Request" +curl "$FLUSO_API/v1/agents/agt_0123456789ab4def8123456789abcdef/versions" \ + -H "Authorization: Bearer $FLUSO_TOKEN" +``` + +```json title="Response: 200, selected fields" +{ + "versions": [ + { + "schemaVersion": 1, + "configId": "cfg_22222222222242228222222222222222", + "agentId": "agt_0123456789ab4def8123456789abcdef", + "goal": "Return a go or no-go decision with named owners", + "createdAt": "2026-08-31T10:00:00Z", + "contentDigest": "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789" + } + ] +} +``` + +To restore an available configuration, send its editable fields through the +normal update endpoint and use the Agent's current `currentConfigId` as +`baseConfigId`. The update creates a new immutable configuration. Existing +chats keep the configuration they started with. + +## Delete an Agent + + + +Deletes the Agent and removes its owned chats, configurations, knowledge, and schedules. + +```bash title="Request" +curl "$FLUSO_API/v1/agents/agt_0123456789ab4def8123456789abcdef" \ + -X DELETE \ + -H "Authorization: Bearer $FLUSO_TOKEN" +``` + +```http title="Response" +HTTP/1.1 204 No Content +``` + +## Next + +Start Agent work through [Threads and messages](/developers/threads-and-messages), or automate it with [Schedules](/developers/schedules). diff --git a/content/docs/developers/architecture.mdx b/content/docs/developers/architecture.mdx new file mode 100644 index 0000000..ae4b987 --- /dev/null +++ b/content/docs/developers/architecture.mdx @@ -0,0 +1,57 @@ +--- +title: Architecture +sidebarTitle: Architecture +icon: network +description: How requests, runtime compute, platform state, workspace data, and external sources fit together. +--- + +Fluso separates request handling, runtime compute, durable workspace data, platform records, and external tools. Those boundaries keep each responsibility visible when you deploy or integrate the platform. + +Client requests enter these boundaries through the [authenticated REST API](/developers/authentication). + + + +## Request path + +1. A Fluso client sends an authenticated request through the edge. +2. The REST API validates identity and handles platform records. +3. The gateway admits work, selects the user's runtime, and routes the request. +4. A thread worker runs the turn with the Agent configuration, tools, and project context attached to that thread. + +The runtime can stop and return later because it does not own the only copy of durable user state. + +## Data ownership + +| Boundary | What it owns | +| ------------------ | ------------------------------------------------------------------------------- | +| PostgreSQL | Users, organizations, access records, schedules, and other platform state | +| Isolated user storage | Projects, session history, Agent definitions, skills, and durable runtime files | +| Knowledge service | Indexed context and retrieval records under its service contract | +| MCP sources | External data and actions exposed by each connected server | + +Project working memory belongs to its project. Agent configuration and chat history have separate records, so changing an Agent does not rewrite old conversations. + +## Replaceable components + +Components can change where the code defines an explicit contract: + +- Runtime compute sits behind a `SandboxProvider` contract. Current implementations cover local Docker and AWS ECS. +- Models resolve through a provider-scoped catalog. Current provider paths cover PCCI and OpenRouter; the catalog does not promise that every model works through every provider. +- Managed apps and custom servers meet the runtime through MCP and the same tool-policy boundary. A source can change while the protocol stays fixed, though tool names and semantics can still differ. +- Services can move behind their HTTP contracts when the replacement preserves authentication, response shape, and failure behavior. + +## Governed external context + +An MCP server advertises tools. User policy decides whether each tool is allowed, denied, or requires approval. Organization policy separately governs network egress. Read-only classification can permit low-risk reads without turning every MCP connection into a read-only connection. + +External data stays under the source system's own controls until an approved tool reads it. Fluso may then persist selected outputs in chat history, project files, or knowledge records according to the requested work and platform policy. + + + Storage independence here means runtime compute does not own durable state. + PostgreSQL, workspace storage, and the knowledge service still have explicit + schemas and operational contracts. + + +## Next + +Start with [Authentication](/developers/authentication), then create an Agent through [Agents and versions](/developers/agents-and-versions). diff --git a/content/docs/developers/authentication.mdx b/content/docs/developers/authentication.mdx new file mode 100644 index 0000000..0d946ce --- /dev/null +++ b/content/docs/developers/authentication.mdx @@ -0,0 +1,135 @@ +--- +title: Authentication +sidebarTitle: Authentication +icon: key-round +description: Authenticate a client and send bearer tokens to the Fluso REST API. +--- + +The REST API base URL is `https://api.fluso.ai`. Set it once, then assign the access token returned by the client sign-in flow: + +The `/v1` routes in this Beta section are the current client surface and may change during beta. Endpoints used only by the Fluso web app are internal and may change without notice. + +```bash +export FLUSO_API=https://api.fluso.ai +export FLUSO_TOKEN='' +``` + +Send that token on every authenticated request: + +```http +Authorization: Bearer $FLUSO_TOKEN +``` + +Keep access and refresh tokens out of source control. The examples below use placeholders and environment variables. + +Once authenticated, start with [Agents and versions](/developers/agents-and-versions). + +## Start client sign-in + + + +Creates a short-lived browser sign-in URL for a CLI or another client. + +```bash title="Request" +curl "$FLUSO_API/v1/auth/client/start" \ + -H 'Content-Type: application/json' \ + -d '{ + "client": "cli", + "client_user_id": "device-123", + "metadata": {"return_to": "fluso://auth"} + }' +``` + +```json title="Response: 200" +{ + "url": "https:///auth/client/launch?state=...", + "expires_in": 600 +} +``` + +Open `url` in the user's browser. The signed-in page completes approval and returns a one-time code to the client. + +## Exchange the one-time code + + + +Consumes the code once and returns credentials bound to the same client and client user ID. + +```bash title="Request" +export FLUSO_CODE='' + +curl "$FLUSO_API/v1/auth/client/exchange/$FLUSO_CODE?client=cli&client_user_id=device-123" +``` + +```json title="Response: 200" +{ + "status": "completed", + "auth": { + "access_token": "", + "refresh_token": "", + "expires_in": 86400, + "aci_api_key": "", + "user": { + "id": "22222222-2222-4222-8222-222222222222", + "email": "developer@example.com", + "name": "Developer" + } + } +} +``` + +The code expires and cannot be exchanged twice. + +## Refresh a client session + + + +Exchanges a valid client refresh token for refreshed credentials. + +```bash title="Request" +curl "$FLUSO_API/v1/auth/client/refresh" \ + -H 'Content-Type: application/json' \ + -d '{"refresh_token":""}' +``` + +```json title="Response: 200" +{ + "access_token": "", + "refresh_token": "", + "expires_in": 86400, + "aci_api_key": "" +} +``` + +## Read the current user + + + +Returns the user attached to the bearer token and their runtime API key. + +```bash title="Request" +curl "$FLUSO_API/v1/auth/me" \ + -H "Authorization: Bearer $FLUSO_TOKEN" +``` + +```json title="Response: 200" +{ + "user": { + "id": "22222222-2222-4222-8222-222222222222", + "email": "developer@example.com", + "name": "Developer", + "picture": null, + "created_at": "2026-08-31T09:00:00" + }, + "aci_api_key": "" +} +``` + + + Workspace and usage routes also expect the bearer header. An `X-API-Key` + header alone does not authenticate those proxy paths. + + +## Next + +Use the token with [Agents and versions](/developers/agents-and-versions), or open a turn through [Threads and messages](/developers/threads-and-messages). diff --git a/content/docs/developers/files-and-projects.mdx b/content/docs/developers/files-and-projects.mdx new file mode 100644 index 0000000..837359d --- /dev/null +++ b/content/docs/developers/files-and-projects.mdx @@ -0,0 +1,231 @@ +--- +title: Files and projects +sidebarTitle: Files & projects +icon: folder-kanban +description: Work with durable project metadata and files in a user's Agent workspace. +--- + +Workspace projects and files use the `/v1/agent/*` routes. They belong to the authenticated user's durable workspace, outside disposable runtime compute. + +[Agents](/developers/agents-and-versions) bind new chats to one of these projects by name. + +## List projects + + + +Returns workspace projects and their thread summaries. + +```bash title="Request" +curl "$FLUSO_API/v1/agent/projects?includeArchived=false" \ + -H "Authorization: Bearer $FLUSO_TOKEN" +``` + +```json title="Response: 200" +{ + "projects": [ + { + "name": "Release Review", + "goal": "Decide launch readiness", + "createdAt": "2026-08-31T09:00:00Z", + "updatedAt": "2026-08-31T09:00:00Z", + "threads": [] + } + ] +} +``` + +## Create a project + + + +Creates a workspace project and its context file. + +```bash title="Request" +curl "$FLUSO_API/v1/agent/projects" \ + -X POST \ + -H "Authorization: Bearer $FLUSO_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{ + "name": "Release Review", + "goal": "Decide launch readiness", + "instructions": "Keep evidence and decisions in this project." + }' +``` + +```json title="Response: 201" +{ + "name": "Release Review", + "goal": "Decide launch readiness", + "instructions": "Keep evidence and decisions in this project.", + "createdAt": "2026-08-31T09:00:00Z", + "updatedAt": "2026-08-31T09:00:00Z", + "threads": [] +} +``` + +## Update a project + + + +Updates the project named in the request body. + +```bash title="Request" +curl "$FLUSO_API/v1/agent/projects" \ + -X PATCH \ + -H "Authorization: Bearer $FLUSO_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{ + "name": "Release Review", + "goal": "Decide launch readiness and record follow-up owners" + }' +``` + +```json title="Response: 200, selected fields" +{ + "name": "Release Review", + "goal": "Decide launch readiness and record follow-up owners", + "updatedAt": "2026-08-31T09:05:00Z", + "threads": [] +} +``` + +## Export a project + + + +Streams the named project as a ZIP archive. + +```bash title="Request" +curl -G "$FLUSO_API/v1/agent/projects/export" \ + -H "Authorization: Bearer $FLUSO_TOKEN" \ + --data-urlencode 'name=Release Review' \ + -o release-review.zip +``` + +```http title="Response" +HTTP/1.1 200 OK +Content-Type: application/zip +Content-Disposition: attachment; filename="Release Review.zip"; filename*=UTF-8''Release%20Review.zip +``` + +## List files + + + +Lists files or directories under a workspace path. + +```bash title="Request" +curl "$FLUSO_API/v1/agent/files?path=/files&recursive=false&includeStats=true" \ + -H "Authorization: Bearer $FLUSO_TOKEN" +``` + +```json title="Response: 200" +{ + "path": "/files", + "recursive": false, + "entries": [ + { + "path": "/files/release-brief.md", + "name": "release-brief.md", + "type": "file", + "size": 1240, + "modifiedAt": "2026-08-31T09:00:00Z", + "mimeType": "text/markdown" + } + ] +} +``` + +## Read a text file + + + +Returns a UTF-8 text file as JSON. + +```bash title="Request" +curl -G "$FLUSO_API/v1/agent/files/read" \ + -H "Authorization: Bearer $FLUSO_TOKEN" \ + --data-urlencode 'path=/files/release-brief.md' +``` + +```json title="Response: 200" +{ + "path": "/files/release-brief.md", + "content": "# Release candidate\n\nKnown issue: ...\n", + "encoding": "utf-8" +} +``` + +## Upload a file + + + +Uploads one file with an optional destination and conflict policy. + +```bash title="Request" +curl "$FLUSO_API/v1/agent/files/upload" \ + -H "Authorization: Bearer $FLUSO_TOKEN" \ + -F 'file=@release-brief.md' \ + -F 'path=/files/release-brief.md' \ + -F 'onConflict=overwrite' +``` + +```json title="Response: 200" +{ + "success": true, + "path": "/files/release-brief.md", + "size": 1240, + "mimeType": "text/markdown" +} +``` + +`onConflict` accepts `error`, `overwrite`, or `uuid`. The default is `error`. + +## Download a file + + + +Streams a file with attachment headers. + +```bash title="Request" +curl -G "$FLUSO_API/v1/agent/files/download" \ + -H "Authorization: Bearer $FLUSO_TOKEN" \ + --data-urlencode 'path=/files/release-report.pdf' \ + -o release-report.pdf +``` + +```http title="Response" +HTTP/1.1 200 OK +Content-Type: application/pdf +Content-Disposition: attachment; filename="release-report.pdf"; filename*=UTF-8''release-report.pdf +``` + +## Delete a file + + + +Deletes one file, or a directory when `recursive=true`. + +```bash title="Request" +curl -G "$FLUSO_API/v1/agent/files" \ + -X DELETE \ + -H "Authorization: Bearer $FLUSO_TOKEN" \ + --data-urlencode 'path=/files/release-brief.md' \ + --data 'recursive=false' +``` + +```json title="Response: 200" +{ + "success": true, + "path": "/files/release-brief.md" +} +``` + + + A recursive directory delete removes every child path. List the target first + when its contents are not already known. + + +## Next + +Attach project context to [Agents and versions](/developers/agents-and-versions), or create project-bound [Threads and messages](/developers/threads-and-messages). diff --git a/content/docs/developers/meta.json b/content/docs/developers/meta.json new file mode 100644 index 0000000..4c27a7f --- /dev/null +++ b/content/docs/developers/meta.json @@ -0,0 +1,12 @@ +{ + "pages": [ + "agents-and-versions", + "architecture", + "authentication", + "files-and-projects", + "runs", + "schedules", + "threads-and-messages", + "usage" + ] +} diff --git a/content/docs/developers/runs.mdx b/content/docs/developers/runs.mdx new file mode 100644 index 0000000..f0cf041 --- /dev/null +++ b/content/docs/developers/runs.mdx @@ -0,0 +1,109 @@ +--- +title: Runs +sidebarTitle: Runs +icon: activity +description: Inspect Agent runs and stop work that is still active. +--- + +Run IDs are request IDs. A run can be `queued`, `running`, `held`, `completed`, `failed`, or `cancelled`. + +Runs originate from [messages](/developers/threads-and-messages) and [schedules](/developers/schedules). + +## List runs + + + +Returns recent runs, with optional thread, request, and attention filters. + +```bash title="Request" +curl "$FLUSO_API/v1/agent-runs?threadId=thread_agent_release&limit=20" \ + -H "Authorization: Bearer $FLUSO_TOKEN" +``` + +```json title="Response: 200" +{ + "agent_runs": [ + { + "id": "req_review_01", + "request_id": "req_review_01", + "thread_id": "thread_agent_release", + "target_thread_id": "thread_agent_release", + "agent_id": "agt_0123456789ab4def8123456789abcdef", + "thread_title": "Release review", + "status": "running", + "origin": "user", + "created_at": "2026-08-31T09:00:00Z", + "started_at": "2026-08-31T09:00:01Z", + "updated_at": "2026-08-31T09:00:02Z", + "completed_at": null, + "outcome": null, + "result_ref": null, + "error": null + } + ], + "settlement_cursor": "2026-08-31T09:00:02Z/req_review_01" +} +``` + +Use `attention=true` to include runs that need review and schedule delivery failures. + +## Read one run + + + +Returns one matching run. Include `threadId` when request IDs may repeat across threads. + +```bash title="Request" +curl "$FLUSO_API/v1/agent-runs/req_review_01?threadId=thread_agent_release" \ + -H "Authorization: Bearer $FLUSO_TOKEN" +``` + +```json title="Response: 200" +{ + "id": "req_review_01", + "request_id": "req_review_01", + "thread_id": "thread_agent_release", + "target_thread_id": "thread_agent_release", + "agent_id": "agt_0123456789ab4def8123456789abcdef", + "status": "completed", + "origin": "user", + "created_at": "2026-08-31T09:00:00Z", + "started_at": "2026-08-31T09:00:01Z", + "updated_at": "2026-08-31T09:01:10Z", + "completed_at": "2026-08-31T09:01:10Z", + "outcome": "completed", + "result_ref": { + "thread_id": "thread_agent_release", + "request_id": "req_review_01" + }, + "error": null +} +``` + +## Stop a run + + + +Requests cancellation without starting a dormant runtime only to stop it. + +```bash title="Request" +curl "$FLUSO_API/v1/agent-runs/req_review_01/stop" \ + -X POST \ + -H "Authorization: Bearer $FLUSO_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{"threadId":"thread_agent_release"}' +``` + +```json title="Response: 200" +{ + "thread_id": "thread_agent_release", + "request_id": "req_review_01", + "status": "cancelled" +} +``` + +The status can also be `already_terminal` when the run settled before cancellation reached it. + +## Next + +Inspect token cost in [Usage](/developers/usage), or create recurring and one-time [Schedules](/developers/schedules). diff --git a/content/docs/developers/schedules.mdx b/content/docs/developers/schedules.mdx new file mode 100644 index 0000000..3f236cb --- /dev/null +++ b/content/docs/developers/schedules.mdx @@ -0,0 +1,139 @@ +--- +title: Schedules +sidebarTitle: Schedules +icon: calendar-clock +description: Create, inspect, pause, and delete Agent schedules. +--- + +A schedule belongs to an Agent and one of that Agent's existing threads. Supply exactly one timing field: a five-field `cron` expression or a future `at` timestamp with an offset. `timezone` must be an IANA time zone. + +See [Threads and messages](/developers/threads-and-messages) for the target thread and [Runs](/developers/runs) for execution state. + +## List schedules + + + +Returns schedules for an Agent, optionally filtered by thread. + +```bash title="Request" +curl "$FLUSO_API/v1/agents/agt_0123456789ab4def8123456789abcdef/schedules?threadId=thread_agent_release&page=1&limit=100" \ + -H "Authorization: Bearer $FLUSO_TOKEN" +``` + +```json title="Response: 200" +{ + "schedules": [ + { + "id": "11111111-1111-4111-8111-111111111111", + "agentId": "agt_0123456789ab4def8123456789abcdef", + "threadId": "thread_agent_release", + "message": "Review the release candidate", + "cron": "0 9 * * 1-5", + "timezone": "Asia/Kolkata", + "status": "active", + "pauseReason": null, + "nextRunAt": "2026-09-01T03:30:00Z", + "attempts": 0, + "createdAt": "2026-08-31T09:00:00Z", + "updatedAt": "2026-08-31T09:00:00Z", + "firedAt": null, + "lastRun": null + } + ], + "pagination": { "page": 1, "limit": 100, "total": 1, "pages": 1 } +} +``` + +## Create a schedule + + + +Creates a recurring or one-time schedule. The caller supplies a UUID so retries can be idempotent. + +```bash title="Request" +curl "$FLUSO_API/v1/agents/agt_0123456789ab4def8123456789abcdef/schedules" \ + -X POST \ + -H "Authorization: Bearer $FLUSO_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{ + "id": "11111111-1111-4111-8111-111111111111", + "threadId": "thread_agent_release", + "message": "Review the release candidate", + "cron": "0 9 * * 1-5", + "timezone": "Asia/Kolkata" + }' +``` + +For a durable one-time schedule, replace `cron` with an offset-bearing `at` value: + +```json title="One-time timing fields" +{ + "at": "2026-09-01T09:00:00+05:30", + "timezone": "Asia/Kolkata" +} +``` + +```json title="Response: 201" +{ + "id": "11111111-1111-4111-8111-111111111111", + "agentId": "agt_0123456789ab4def8123456789abcdef", + "threadId": "thread_agent_release", + "message": "Review the release candidate", + "cron": "0 9 * * 1-5", + "timezone": "Asia/Kolkata", + "status": "active", + "pauseReason": null, + "nextRunAt": "2026-09-01T03:30:00Z", + "attempts": 0, + "createdAt": "2026-08-31T09:00:00Z", + "updatedAt": "2026-08-31T09:00:00Z", + "firedAt": null, + "lastRun": null +} +``` + +Replaying the same ID and body returns the existing schedule with `200`. Reusing the ID with different fields returns a conflict. + +## Pause or edit a schedule + + + +Updates submitted fields. `threadId` is always required to guard the target. + +```bash title="Request" +curl "$FLUSO_API/v1/agents/agt_0123456789ab4def8123456789abcdef/schedules/11111111-1111-4111-8111-111111111111" \ + -X PATCH \ + -H "Authorization: Bearer $FLUSO_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{"threadId":"thread_agent_release","status":"paused"}' +``` + +```json title="Response: 200, selected fields" +{ + "id": "11111111-1111-4111-8111-111111111111", + "agentId": "agt_0123456789ab4def8123456789abcdef", + "threadId": "thread_agent_release", + "status": "paused", + "nextRunAt": "2026-09-01T03:30:00Z" +} +``` + +## Delete a schedule + + + +Deletes a schedule after matching it to the supplied thread. + +```bash title="Request" +curl "$FLUSO_API/v1/agents/agt_0123456789ab4def8123456789abcdef/schedules/11111111-1111-4111-8111-111111111111?threadId=thread_agent_release" \ + -X DELETE \ + -H "Authorization: Bearer $FLUSO_TOKEN" +``` + +```http title="Response" +HTTP/1.1 204 No Content +``` + +## Next + +Inspect each execution in [Runs](/developers/runs), or manage the target in [Threads and messages](/developers/threads-and-messages). diff --git a/content/docs/developers/threads-and-messages.mdx b/content/docs/developers/threads-and-messages.mdx new file mode 100644 index 0000000..c59a7b4 --- /dev/null +++ b/content/docs/developers/threads-and-messages.mdx @@ -0,0 +1,174 @@ +--- +title: Threads and messages +sidebarTitle: Threads & messages +icon: messages-square +description: Create threads, manage their metadata, read history, and stream a turn. +--- + +Threads live inside a workspace project. Thread responses use snake_case fields. The chat stream follows the AI SDK UI message stream protocol. + +Agent-backed threads use an [Agent configuration](/developers/agents-and-versions), and each accepted turn creates a [run](/developers/runs). + +## List threads + + + +Returns ordinary threads ordered by recent activity. + +```bash title="Request" +curl "$FLUSO_API/v1/threads?page=1&limit=20" \ + -H "Authorization: Bearer $FLUSO_TOKEN" +``` + +```json title="Response: 200, selected fields" +{ + "threads": [ + { + "thread_id": "thread_release", + "project_id": "Release Review", + "name": "Release review", + "title": "Release review", + "created_at": "2026-08-31T09:00:00Z", + "updated_at": "2026-08-31T09:02:00Z", + "last_active_at": "2026-08-31T09:02:00Z", + "status": "ready" + } + ], + "pagination": { "page": 1, "limit": 20, "total": 1, "pages": 1 } +} +``` + +Agent-owned chats are omitted from this general list and remain attached to their Agent. + +## Create a thread + + + +Creates a thread in the named project, creating the project when needed. + +```bash title="Request" +curl "$FLUSO_API/v1/threads" \ + -X POST \ + -H "Authorization: Bearer $FLUSO_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{"project_id":"Release Review","title":"Release review"}' +``` + +```json title="Response: 200" +{ + "thread_id": "thread_release", + "project_id": "Release Review" +} +``` + +You can supply your own `thread_id` for an idempotent integration boundary. + +## Update a thread + + + +Updates the title, metadata, pin, archive state, or label membership. + +```bash title="Request" +curl "$FLUSO_API/v1/threads/thread_release?project_id=Release%20Review" \ + -X PATCH \ + -H "Authorization: Bearer $FLUSO_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{"title":"RC decision","pinned":true}' +``` + +```json title="Response: 200, selected fields" +{ + "thread_id": "thread_release", + "project_id": "Release Review", + "name": "RC decision", + "title": "RC decision", + "pinned_at": "2026-08-31T09:03:00Z", + "status": "ready" +} +``` + +## Read message history + + + +Returns the thread's persisted messages and projected tool-status records. + +```bash title="Request" +curl "$FLUSO_API/v1/threads/thread_release/messages?project_id=Release%20Review" \ + -H "Authorization: Bearer $FLUSO_TOKEN" +``` + +```json title="Response: 200" +{ + "messages": [ + { + "message_id": "user-1", + "thread_id": "thread_release", + "type": "user", + "is_llm_message": false, + "content": "{\"content\":\"Review this release candidate\"}", + "metadata": "{\"request_id\":\"req_review_01\"}", + "created_at": "2026-08-31T09:00:00Z", + "updated_at": "2026-08-31T09:00:00Z" + } + ] +} +``` + +## Send a message + + + +Starts or queues a turn and streams UI message events until the request settles. + +Use a new thread ID for the first Agent-backed turn. The accepted send creates and binds that thread; an ordinary thread cannot later be converted. + +```bash title="Request" +curl -N "$FLUSO_API/v1/chat" \ + -H "Authorization: Bearer $FLUSO_TOKEN" \ + -H 'Content-Type: application/json' \ + -d '{ + "threadId": "thread_agent_release", + "projectName": "Release Review", + "agentId": "agt_0123456789ab4def8123456789abcdef", + "requestId": "req_review_01", + "message": "Review this release candidate" + }' +``` + +```text title="Response: 200 text/event-stream, shortened" +data: {"type":"start","messageId":"assistant-req_review_01"} + +data: {"type":"text-start","id":"final-text-req_review_01"} + +data: {"type":"text-delta","id":"final-text-req_review_01","delta":"Go, with one follow-up."} + +data: {"type":"text-end","id":"final-text-req_review_01"} + +data: {"type":"finish"} + +data: [DONE] +``` + +Use one unique `requestId` per intended turn. Retrying the same accepted request does not create a second turn. + +## Delete a thread + + + +Deletes the thread and removes schedules that target it. + +```bash title="Request" +curl "$FLUSO_API/v1/threads/thread_release?project_id=Release%20Review" \ + -X DELETE \ + -H "Authorization: Bearer $FLUSO_TOKEN" +``` + +```json title="Response: 200" +{ "deleted": true } +``` + +## Next + +Bind new threads to [Agents and versions](/developers/agents-and-versions), or follow accepted turns in [Runs](/developers/runs). diff --git a/content/docs/developers/usage.mdx b/content/docs/developers/usage.mdx new file mode 100644 index 0000000..37dd4e5 --- /dev/null +++ b/content/docs/developers/usage.mdx @@ -0,0 +1,144 @@ +--- +title: Usage +sidebarTitle: Usage +icon: chart-no-axes-combined +description: Read current-user totals, session summaries, and filtered raw usage entries. +--- + +Usage records are user-scoped. Token counts and costs use camelCase fields, and cost values are denominated in US dollars. + +Filter entries by the request and thread identifiers returned from [Runs](/developers/runs). + +## Read usage totals + + + +Returns totals for the current user plus a map of session summaries. + +```bash title="Request" +curl "$FLUSO_API/v1/token-usage" \ + -H "Authorization: Bearer $FLUSO_TOKEN" +``` + +```json title="Response: 200, selected fields" +{ + "userId": "22222222-2222-4222-8222-222222222222", + "lastUpdated": "2026-08-31T09:05:00Z", + "totals": { + "tokens": { + "input": 120, + "output": 40, + "cacheRead": 0, + "cacheWrite": 0, + "total": 160 + }, + "cost": { + "input": 0.001, + "output": 0.002, + "cacheRead": 0, + "cacheWrite": 0, + "total": 0.003 + }, + "entryCount": 1 + } +} +``` + +## List session summaries + + + +Returns the session map from the totals response as an array. + +```bash title="Request" +curl "$FLUSO_API/v1/token-usage/sessions" \ + -H "Authorization: Bearer $FLUSO_TOKEN" +``` + +```json title="Response: 200, selected fields" +[ + { + "sessionId": "sess_ddf284f4", + "threadId": "thread_agent_release", + "firstSeen": "2026-08-31T09:00:00Z", + "lastUpdated": "2026-08-31T09:05:00Z", + "entryCount": 1, + "tokens": { + "input": 120, + "output": 40, + "cacheRead": 0, + "cacheWrite": 0, + "total": 160 + }, + "cost": { + "input": 0.001, + "output": 0.002, + "cacheRead": 0, + "cacheWrite": 0, + "total": 0.003 + } + } +] +``` + +## List usage entries + + + +Returns raw usage entries that match the submitted filters. + +```bash title="Request" +curl "$FLUSO_API/v1/token-usage/entries?threadId=thread_agent_release&limit=100" \ + -H "Authorization: Bearer $FLUSO_TOKEN" +``` + +```json title="Response: 200, selected fields" +[ + { + "schemaVersion": 2, + "eventId": "use_0123456789abcdef0123456789abcdef", + "source": "pi-provider", + "ts": "2026-08-31T09:05:00Z", + "sessionId": "sess_ddf284f4", + "threadId": "thread_agent_release", + "component": "chat-agent", + "measurement": "actual", + "requestId": "req_review_01", + "provider": "openrouter", + "status": "success", + "model": "provider/model-id", + "tokens": { + "input": 120, + "output": 40, + "cacheRead": 0, + "cacheWrite": 0, + "total": 160 + }, + "cost": { + "input": 0.001, + "output": 0.002, + "cacheRead": 0, + "cacheWrite": 0, + "total": 0.003 + }, + "costSource": "provider" + } +] +``` + +| Parameter | Matches | Default | +| --- | --- | --- | +| `sessionId` | Session ID | - | +| `threadId` | Thread ID | - | +| `requestId` | Request ID | - | +| `component` | Emitting component | - | +| `provider` | Model provider | - | +| `providerSessionId` | Provider session ID | - | +| `providerGenerationId` | Provider generation ID | - | +| `model` | Model ID | - | +| `since` | Entries at or after an RFC 3339 instant | - | +| `limit` | Maximum entries, from 1 through 1000 | `100` | + +## Next + +Correlate costs with [Runs](/developers/runs), or review the service boundaries in [Architecture](/developers/architecture). diff --git a/content/docs/features/chat.mdx b/content/docs/features/chat.mdx index 8abdc65..35a13c9 100644 --- a/content/docs/features/chat.mdx +++ b/content/docs/features/chat.mdx @@ -8,10 +8,6 @@ Chat is the front door. You tell Fluso what to do in plain English, and it does ## What happens when you send a message - - **Video —** Short demo (10–15s) of one multi-tool request: user types *"Summarise my unread emails and create tasks from the actionable ones"*, and the response unfolds — Gmail querying, drafts forming, tasks appearing, and a short summary at the end. - - A small pause between hitting enter and seeing the first words come back. In that pause, Fluso gathers everything it has on the situation. The thread's history. Your project's memory. Your connected apps. The skills available. The files in scope. Your preferences. Then it picks tools and uses them. Sometimes one. Sometimes ten in a row. Ask it to summarise your unread emails and create tasks from the actionable ones. Behind the scenes, it queries Gmail, finds twelve unread, reads the five that look like requests, drafts three tasks with deadlines, drops them into your task list, and writes a short summary. You see the summary. The work is already done. diff --git a/content/docs/features/confidential.mdx b/content/docs/features/confidential.mdx index 3402110..c380910 100644 --- a/content/docs/features/confidential.mdx +++ b/content/docs/features/confidential.mdx @@ -4,7 +4,7 @@ sidebarTitle: Confidential description: Run your work through models hosted in a hardware-sealed enclave. --- -Confidential mode routes your inference through Prem API's confidential compute, an isolated enclave that infrastructure operators and the cloud provider cannot access. It's available on the Max plan and, once enabled, it stays on. The sections below cover what it adds, how to switch it on from Settings, and what to expect once it's active. +Confidential mode routes your inference through Prem API's confidential compute, an isolated enclave that infrastructure operators and the cloud provider cannot access. It is available on the Confidential plan. You can turn it off later to return future requests to standard provider routing. ## What it protects @@ -18,70 +18,42 @@ For the full technical picture, see Prem's [confidential compute documentation]( ## Plans -Confidential mode is a Max plan feature. Every Fluso account starts on a sponsored Pro plan, which covers normal inference at no cost to you. The setting lives in **Settings** under **Confidential APIs**, and on the sponsored Pro plan it reads "Available on the Max plan" with an **Upgrade** button. +Confidential mode is included with the **Confidential** plan. Accounts granted access by the Fluso team show **Sponsored Confidential** as their effective plan. -Open your profile from the bottom of the left sidebar. The plan you're on shows next to **Manage plan**. - - - Fluso account menu opened from the bottom of the left sidebar, showing Settings, Manage account, and Manage plan with a Sponsored Pro badge. - - -Open **Settings**. The Confidential APIs row reads "End-to-end encrypted inference. Available on the Max plan" with an **Upgrade** button on the right. - - - Fluso Settings page. The Confidential APIs row reads 'End-to-end encrypted inference. Available on the Max plan' with an Upgrade button. Billing reads Sponsored Pro plan. - +Open **Settings** and find **Encrypted Inference**. Without plan access, the row reads "Available on the Confidential plan" and shows **Upgrade**. With plan access, it shows an **Off** or **On** switch. ## Turning it on - - From the Confidential APIs prompt or **Settings → Plans**, pick **Max** and complete checkout. New accounts get a 30-day free trial. - - - Plans grid showing Basic, Plus, Pro, and Max. The Max card reads '$119/month — all the advantages of the Pro plan with the most private settings'. - + + Open **Settings → Plans** and choose **Confidential**. If your team grants sponsored access, the current plan reads **Sponsored Confidential** instead. - - With Max active, you can flip the toggle. The panel notes that the change is permanent first: "Permanent once enabled. Requests stay on confidential inference; image generation and automated task creation are disabled." - - - Confidential APIs panel on the Max plan: the toggle is enabled and a note reads 'Permanent once enabled. Requests stay on confidential inference; image generation and automated task creation are disabled.' Billing reads Max plan. - - - A dialog confirms the one-way switch and lists what gets disabled in this mode. - - - Turn on confidential mode dialog: 'Every request routes through end-to-end encrypted inference. Permanent — it can't be turned off once enabled.' Disabled in this mode: automated task generation, image generation. Cancel and Enable permanently buttons. - + + Turn on the switch under **Settings → Encrypted Inference**. The confirmation dialog lists the two unavailable capabilities: automated task generation and image generation. It also explains that you can return to standard inference later, but data removed during activation cannot be restored automatically. - The panel turns green and the toggle reads **On**. From here on, your inference runs through the enclave. - - - Confidential APIs panel in the active state: green shield icon, On toggle, green background, and a note that image generation and automated task creation are disabled in this mode. Billing reads Max plan. - + The panel turns green and the switch reads **On**. New inference requests now run through the enclave. - Enabling confidential mode is permanent. Once your workspace is in confidential mode, you can't switch back to standard inference. Image generation and automated task creation are disabled while it's on. + Switching back changes future requests to standard provider routing and makes image generation and automated task creation available again. Existing conversations and context may use standard routing in later requests. Data removed during activation cannot be restored automatically. ## FAQ - No. Turning on confidential mode is a one-way change for your workspace. Once you're in confidential mode, there's no path back to standard inference. + Yes. Turn the **Encrypted Inference** switch off and confirm **Use standard inference**. Future requests use standard provider routing, and image generation and automated task creation become available again. Confidential mode never falls back to standard inference, because a silent fallback would route your data through a non-confidential path. If the enclave can't be reached, the request fails and you'll see an error instead. Retry once the enclave is reachable again. If it stays down, [contact support](mailto:support@premai.io). - Image generation and automated task creation. Both rely on paths that would take your data outside the enclave, so they're turned off in this mode. Everything else keeps working. + Image generation and automated task creation. Both rely on paths that would take your data outside the enclave, so they're turned off in this mode. - The Max plan. Every account starts on a sponsored Pro plan, which runs normal inference. Confidential mode is the reason to move to Max. New accounts can start a 30-day Max trial. + The Confidential plan. Team-granted access appears as Sponsored Confidential. Inside the enclave, no. At the gateway, your request is encrypted for a hardware-sealed environment that infrastructure operators and the cloud provider cannot access. Before that, traffic passes through Fluso's AWS infrastructure. diff --git a/content/docs/features/mcp.mdx b/content/docs/features/mcp.mdx index e0f443a..1da0fb2 100644 --- a/content/docs/features/mcp.mdx +++ b/content/docs/features/mcp.mdx @@ -9,7 +9,7 @@ Fluso reaches other software through MCP. There is no separate connector system Two ways in, one list: - **Apps.** A catalog of about a hundred managed apps — Google Workspace, GitHub, Slack, Linear, Notion, Jira, HubSpot, Stripe, and so on. One click, sign in on the app's own page, done. Fluso runs the MCP server for you. -- **Custom server.** Any MCP-compatible endpoint, by URL. Your team's private server, a smaller SaaS that shipped an MCP endpoint, a tool a developer stood up over the weekend. +- **Custom server.** A publicly reachable HTTPS endpoint that implements MCP over Streamable HTTP. This can be a server your team operates or a SaaS endpoint outside the managed catalog. ## Where to find them @@ -41,6 +41,13 @@ The catalog runs from the everyday — Outlook, Teams, Notion, Dropbox, Zoom — Switch to the **Custom server** tab and paste the endpoint URL. + + Use the exact Streamable HTTP endpoint. It must be reachable from Fluso over + public HTTPS; `localhost`, private network addresses, and `stdio` commands + are not connection URLs. The workspace or organization network-egress + policy, plus any provider policy applied to that origin, must allow it. + + The Add MCP dialog on the Custom server tab, with a single URL field showing the placeholder https://mcp.linear.app. @@ -82,7 +89,7 @@ A static token sent as `Authorization: Bearer ` — the GitHub-PAT style. - Whatever you paste goes to the backend over HTTPS and is stored encrypted at rest, the same way OAuth tokens are. It never sits in the browser and doesn't appear in logs. + Whatever you paste goes to the backend over HTTPS and is stored encrypted at rest, the same way OAuth tokens are. The UI does not persist or redisplay it after save, and it does not appear in logs. ## Connecting from chat @@ -127,7 +134,7 @@ Each row shows the connection's status. The three-dot menu holds the two actions - **Connections are per account, not per chat.** Sign in once; every new chat can use the connection, and it survives runtime restarts in the background. - **The runtime never stores tokens.** Tools fetch a short-lived token from the backend per request, use it, and drop it. Sign-in happens on the app's own page — Fluso never sees your password. -- **Any MCP server works.** OAuth with or without auto-registration, API keys, bearer tokens. Nothing is blocked because of how the server handles sign-in. +- **Custom servers have prerequisites.** Fluso supports public HTTPS Streamable HTTP endpoints with OAuth, API-key, or bearer-token access. A successful sign-in does not override network-egress or provider policy. - **Rules set by your organization take precedence** over anything you allow yourself. diff --git a/content/docs/features/skills.mdx b/content/docs/features/skills.mdx index 3e18326..c891e79 100644 --- a/content/docs/features/skills.mdx +++ b/content/docs/features/skills.mdx @@ -32,7 +32,7 @@ Naming a skill in your prompt is rarely worth it. Describe the result. The right Fluso Skills page with three sections: My Skills (Podcast Production, Sherlock Holmes), Discover (Fli Flight Search), and Included with Fluso, with an Add skill button at the top right. -Open **Customization** in the left sidebar, then the **Skills** tab. Three sections. +Open **Plugins → Skills** in the left sidebar. Three sections. **My Skills.** Skills this workspace can use right now. Marketplace skills you have added and skills you have built with Fluso live here. Each card has a **Remove** button. @@ -56,6 +56,19 @@ Click any card. A side panel opens with three sections. The skill document is view-only. To change what a skill does, build a new one. +## Private enterprise skills + +Private enterprise skills use two pieces: + +1. `SKILL.md` contains the routing description and operating instructions. +2. An authenticated private MCP server keeps sensitive code and credentials, then exposes the operations the skill needs. + +The server must expose a publicly reachable HTTPS Streamable HTTP endpoint. "Private" here means access-controlled, not a `localhost` or private-network address. The workspace or organization network-egress policy, plus any provider policy applied to that origin, must allow it. + +Access follows the server's authentication and the workspace's MCP tool policy. Each tool's **Allow**, **Ask**, or **Deny** rule controls how calls proceed. Installing the skill does not override server access. See [Apps & MCP](/features/mcp#tool-permissions) to connect the server and set its tool rules. + +This is a deployment pattern for teams that operate their own server. It does not make sensitive content inside `SKILL.md` private or provide a self-service secret store. + ## Adding from the marketplace In **Discover**, find a skill that fits and click **+ Add**. It moves into **My Skills** and is ready on the next message. diff --git a/content/docs/going-deeper.mdx b/content/docs/going-deeper.mdx index 5b50ffb..c127e99 100644 --- a/content/docs/going-deeper.mdx +++ b/content/docs/going-deeper.mdx @@ -61,7 +61,7 @@ The first PR Fluso writes after you add this will make the value obvious. Skills are the prebuilt capabilities Fluso reaches for when a request needs them: PDF generation, deep research, meeting intelligence, image generation, and so on. You can build your own — without writing code or markdown. -A custom skill captures a workflow you repeat with the same shape: a weekly investor update, a standard offer letter, a board-prep checklist. To build one, open **Customization → Skills**, click **Add skill** at the top right, and pick **Build with Fluso**. You land back in chat with a prompt ready to send: +A custom skill captures a workflow you repeat with the same shape: a weekly investor update, a standard offer letter, a board-prep checklist. To build one, open **Plugins → Skills**, click **Add skill** at the top right, and pick **Build with Fluso**. You land back in chat with a prompt ready to send: > *"Create a skill using skill-creator. First, ask what workflow it should handle."* @@ -107,7 +107,7 @@ The pattern: name the inputs, name the output, let Fluso connect them. ## Approval discipline -Reads happen freely. Writes wait for approval. The approval is conversational: when Fluso has a message or change ready to send, it ends its reply with something like *"Shall I send this to sarah@acme.com?"* and waits for your yes or no in chat. +Approval follows the effective tool and chat policy. With **Ask**, a read or write pauses on an approval card. A tool set to **Allow**, or a chat using **Don't ask permission**, can continue without a per-action prompt; **Deny** always blocks it. Keep external-facing write tools on **Ask** when you want to review each draft. The instinct on day one is to read every draft carefully. By day twenty, you will be tempted to wave things through. Don't. @@ -127,7 +127,7 @@ Team plans add shared context. The patterns that matter: **Shared knowledge graph** for the team. Decisions made in any team member's meetings are visible to everyone (within the shared project). Useful for executive teams; less useful for projects with strict need-to-know. -**Admin visibility, not access.** Admins can see which apps team members have connected and how much they're using Fluso. They cannot read messages, files, or knowledge graphs. The audit trail is for managing the seat, not surveilling the work. +**Admin visibility, not content access.** The current browser admin covers local identity and access records. Connected-app inventory, seat controls, and durable audit require a server-side Enterprise integration. The admin UI does not expose messages, files, or knowledge graphs. ## Things people miss diff --git a/content/docs/index.mdx b/content/docs/index.mdx index 26d586b..d109b17 100644 --- a/content/docs/index.mdx +++ b/content/docs/index.mdx @@ -53,6 +53,12 @@ Pick a workflow that matches a problem you have right now. Each one is a story, The connection model and the full catalog of supported apps. + + Authenticate a client and use the versioned REST API. + + + Request flow, durable data boundaries, and replaceable components. + Plans, limits, billing. diff --git a/content/docs/integrations/github.mdx b/content/docs/integrations/github.mdx index 983406e..d1981a8 100644 --- a/content/docs/integrations/github.mdx +++ b/content/docs/integrations/github.mdx @@ -4,7 +4,7 @@ sidebarTitle: GitHub description: Connect GitHub. Setup, repository scope, common prompts, and the project-context pattern that makes generated code fit your codebase. --- -Connecting GitHub turns Fluso into a development partner. It reads your repos, reviews PRs, scaffolds projects, finds and fixes bugs, and manages issues. Every write — PR, commit, issue close — waits for your explicit approval. +Connecting GitHub turns Fluso into a development partner. It reads your repos, reviews PRs, scaffolds projects, finds and fixes bugs, and manages issues. GitHub writes follow each tool's effective **Allow**, **Ask**, or **Deny** policy. If you don't write code, the rest of this page is safely ignorable. If you do, this is the connection that pays back fastest after Gmail. @@ -14,7 +14,7 @@ Open **Plugins** in the sidebar, click **Add MCP**, and click **Connect** on **G Choose repository scope on GitHub's screen: specific repositories or all repositories you have access to. Either is fine, and you can change the set later from your GitHub settings without reconnecting. -Read access is what lets Fluso browse code, answer architecture questions, and review PRs. Write access to issues and PRs is what lets it file issues, open PRs, and leave comments — always with your approval. +Read access is what lets Fluso browse code, answer architecture questions, and review PRs. Write access to issues and PRs is what lets it file issues, open PRs, and leave comments, subject to the effective tool and chat policy. ## Prompts that work well @@ -57,7 +57,7 @@ Issues: > *"What issues are assigned to me this sprint?"* - Fluso always asks before opening a PR, committing code, or closing an issue. The diff or comment is shown for review every time. + Keep GitHub write tools on **Ask** when you want every diff or comment shown before the action runs. **Allow** or **Don't ask permission** can continue without a per-action prompt; **Deny** blocks the write. ## A small thing that makes generated code much better diff --git a/content/docs/integrations/gmail.mdx b/content/docs/integrations/gmail.mdx index 93ee1c8..74a7ea2 100644 --- a/content/docs/integrations/gmail.mdx +++ b/content/docs/integrations/gmail.mdx @@ -21,7 +21,7 @@ You ask Fluso to summarise your inbox, search for something specific, draft a re Gmail comes in through the **Google Workspace** app, which also covers Calendar, Drive, Docs, Sheets, Slides, Meet, and Tasks in one sign-in. -Open **Plugins** in the sidebar, click **Add MCP**, and click **Connect** on **Google Workspace**. Sign in to Google with the account you want Fluso to assist with and approve the permissions on Google's own screen. Reading powers summaries, search, and task extraction; sending is for reply drafts, and Fluso never sends without your approval. +Open **Plugins** in the sidebar, click **Add MCP**, and click **Connect** on **Google Workspace**. Sign in to Google with the account you want Fluso to assist with and approve the permissions on Google's own screen. Reading powers summaries, search, and task extraction. Sending follows the Gmail tool's effective **Allow**, **Ask**, or **Deny** policy. A click and a confirmation screen. You can also just ask in chat — *"connect my Gmail"* — and approve the access card that appears. @@ -61,9 +61,9 @@ Follow-ups: Reading happens when you ask for it (*"summarise my inbox"*) and continuously in the background for auto-task extraction. Messages are processed for the response and not stored beyond what's referenced in your knowledge graph and tasks. -Sending requires your explicit approval. Drafts are always shown first. There's no batch-send mode that bypasses the review. +Keep Gmail send tools on **Ask** when you want every draft shown before it sends. **Allow** or **Don't ask permission** can continue without a per-action prompt; **Deny** blocks the send. There is no separate batch-send mode that overrides the effective policy. -Header metadata is used for categorisation only and never shared with third parties. +Header metadata is used for categorisation and handled under the same subprocessor controls as other requested email content. ## Disconnecting diff --git a/content/docs/integrations/slack.mdx b/content/docs/integrations/slack.mdx index 66698a8..f292664 100644 --- a/content/docs/integrations/slack.mdx +++ b/content/docs/integrations/slack.mdx @@ -12,7 +12,7 @@ If your team mostly coordinates outside Slack, this connection isn't urgent. If Open **Plugins** in the sidebar, click **Add MCP**, and click **Connect** on **Slack**. The Slack authorisation screen asks which workspace to connect; pick the one you want. You can connect more than one if you split work across them. -Reading messages in authorised channels is what powers catching up, search, and surfacing action items. Sending is for posting updates, and Fluso never posts without your approval. +Reading messages in authorised channels is what powers catching up, search, and surfacing action items. Posting follows the Slack tool's effective **Allow**, **Ask**, or **Deny** policy. The catalog also has **Slackbot**, which connects with a bot token instead of your own account. Most people want plain Slack. @@ -47,7 +47,7 @@ Posting: > *"Post a status update in #partnerships about Acme."* - Fluso never posts without your explicit approval. The draft is always shown first. + Keep Slack write tools on **Ask** when you want every draft shown before it posts. **Allow** or **Don't ask permission** can continue without a per-action prompt; **Deny** blocks the post. ## Cross-app workflows diff --git a/content/docs/meta.json b/content/docs/meta.json index b03e88c..501694f 100644 --- a/content/docs/meta.json +++ b/content/docs/meta.json @@ -1,6 +1,8 @@ { "pages": [ "index", + "---Agents (Beta)---", + "...developers", "---Get started---", "introduction", "quickstart", diff --git a/content/docs/quickstart.mdx b/content/docs/quickstart.mdx index 7607034..2cf8e31 100644 --- a/content/docs/quickstart.mdx +++ b/content/docs/quickstart.mdx @@ -126,11 +126,6 @@ Then ask for one useful output: Good prompts name the outcome. Great prompts also name the audience, format, source material, and deadline. - -🎥 **Demo clip — 15 to 25 seconds. P1. Covers Step 5 and Step 6 together.** -One continuous take: user types *"Summarise this project. What is decided, what is unclear, and what should I do next?"* The answer streams in. Citations expand on hover. A task auto-generates in a side panel. This is where Fluso "clicks" for a non-technical reader. - - ## Step 6: review the result Read the answer like you would review work from a person. diff --git a/content/docs/release-notes.mdx b/content/docs/release-notes.mdx index db6ebae..0a2d718 100644 --- a/content/docs/release-notes.mdx +++ b/content/docs/release-notes.mdx @@ -20,7 +20,7 @@ description: "What's new in Fluso - product updates, improvements, and fixes." - Most organisations want agents doing real work, and are wary of letting them loose on company systems. - Fluso makes that a setting rather than a leap of faith. - Every tool on every connection carries its own [allow, ask or deny](https://docs.fluso.ai/features/approvals). -- An agent can read your Gmail freely, while sending an email always stops for your approval. +- Read-only tools can run automatically, while write tools follow their effective **Allow**, **Ask**, or **Deny** rule. - The same split works across Slack, Drive, your trackers and anything else you connect. - Your decisions are durable, and survive reloads and restarts. - Each one shows whether it came from your organisation or from you. @@ -251,7 +251,7 @@ description: "What's new in Fluso - product updates, improvements, and fixes." - Voice notes come back as proper sentences, with punctuation and capitalisation. **Smarter assistant** -- Emails the assistant drafts arrive as properly formatted HTML and sign off with "Sent via fluso.ai", which you can turn off or rename. You still approve every message before it sends. +- Emails the assistant drafts arrive as properly formatted HTML and sign off with "Sent via fluso.ai", which you can turn off or rename. Gmail sends follow the effective tool and chat approval policy. **Reliability, privacy & trust** - On the Max plan, turn on "Confidential APIs" from settings or the chat composer. It's a one-way switch: while it's on, file uploads, image generation, and background syncing pause so nothing leaves the private path. diff --git a/content/docs/remote/telegram.mdx b/content/docs/remote/telegram.mdx index c889914..5ad3117 100644 --- a/content/docs/remote/telegram.mdx +++ b/content/docs/remote/telegram.mdx @@ -57,7 +57,7 @@ Once you are signed in and have at least one app connected, ask in plain English If you ask for something that needs an app you have not connected yet, the bot will say so. Send `/connect ` and ask again. -Before Fluso sends anything for you (an email, a Slack message, a new issue), it shows you the draft and waits for your yes. Nothing goes out without your approval. +Connector writes in Telegram follow the same effective **Allow**, **Ask**, or **Deny** policy as the app. With **Ask**, the bot shows an approval card and waits for your decision. **Allow** or **Don't ask permission** can continue without a per-action prompt; **Deny** blocks the action. ## Fast mode diff --git a/content/docs/resources/faq.mdx b/content/docs/resources/faq.mdx index c8d1a91..e415571 100644 --- a/content/docs/resources/faq.mdx +++ b/content/docs/resources/faq.mdx @@ -65,10 +65,10 @@ description: The questions that come up most often. What Fluso is, how it works, - It reads emails when you ask it to (e.g., *"summarise my inbox"*) and as part of auto-task extraction. It doesn't permanently store copies or share them. + It reads emails when you ask it to (e.g., *"summarise my inbox"*) and as part of auto-task extraction. It does not keep a separate mailbox copy; requested content is processed under the controls described in [Privacy](/resources/privacy). - Never. Drafts always wait for your explicit approval. + Gmail send tools follow your effective **Allow**, **Ask**, or **Deny** policy. Use **Ask** to review each draft before it sends; **Allow** or **Don't ask permission** can continue without a per-action prompt. In your isolated workspace on encrypted infrastructure. Files, conversations, tasks, and the knowledge graph are private to you. diff --git a/content/docs/resources/pricing.mdx b/content/docs/resources/pricing.mdx index 79c2359..7dc3864 100644 --- a/content/docs/resources/pricing.mdx +++ b/content/docs/resources/pricing.mdx @@ -1,12 +1,12 @@ --- title: Pricing sidebarTitle: Pricing -description: Free, Plus, Pro, and Enterprise. Open-source models, European hosting, your data stays yours. +description: Compare plan limits, storage, automation, and workspace controls. --- -Four plans. Free is enough to try Fluso on real work. Plus is for daily use. Pro adds heavier automation and confidential computing. Enterprise covers SSO, audit logs, and custom deployments. +Four plans. Free is enough to try Fluso on real work. Plus is for daily use. Pro adds heavier automation and confidential computing. Enterprise is the path for custom deployments, data residency, and server-integrated identity or audit work. -Everything Fluso runs on is open-source models hosted in Europe. No proprietary APIs. Your data never trains shared models. You get roughly 3× the tokens of equivalent closed-source assistants on the same task. +Model routing depends on the feature. Fluso uses both open-weight models and proprietary model APIs; Agent Studio currently uses Gemini through OpenRouter. Your data never trains shared models. You get roughly 3× the tokens of equivalent closed-source assistants on the same task. ## Plans @@ -56,26 +56,26 @@ Everything Fluso runs on is open-source models hosted in Europe. No proprietary For organisations with custom needs. - Everything in Pro - - SSO + - Server-integrated identity (implementation scoped) - Dedicated account executive - Dedicated support - Custom obligation detection - Encrypted sandbox - Custom data retention - - Audit logs + - Server-backed audit logging (implementation scoped) - Custom skills - **Enterprise.** SOC 2 Type II in place. ISO 27001 in progress. [Get in touch.](mailto:sales@premai.io) + **Enterprise.** Prem has attained SOC 2 Type I; Type II is underway. [Review the current security posture.](https://www.premai.io/security-at-prem) ## What's in every plan A few things hold regardless of plan. -- **Open-source models only.** No proprietary APIs in the pipeline. +- **Feature-specific model routing.** Some features use open-weight models, while others use proprietary model APIs. Agent Studio currently uses Gemini through OpenRouter. - **European hosting.** GDPR-aligned by default. - **3× more tokens** than equivalent closed-source assistants on a like-for-like task. - **Your data is yours.** Nothing trains shared models. @@ -96,8 +96,8 @@ A few things hold regardless of plan. | Confidential computing | — | — | ✅ | ✅ | | Unlimited meeting notes | — | — | ✅ | ✅ | | Priority support | — | — | ✅ | Dedicated | -| SSO | — | — | — | ✅ | -| Audit logs | — | — | — | ✅ | +| SSO | — | — | — | Scoped integration | +| Audit logs | — | — | — | Scoped integration | | Custom skills | — | — | — | ✅ | | Custom data retention | — | — | — | ✅ | @@ -110,7 +110,7 @@ Obligation detection scans your connected apps for things you have committed to: Compared against equivalent closed-source assistants on a like-for-like task. The full methodology lives on the [pricing page](https://fluso.ai/pricing.html). - Open-weight models only, hosted on European infrastructure. No closed-source APIs in the pipeline. + The model depends on the feature. Fluso uses open-weight models for some workloads and proprietary model APIs for others. Agent Studio currently uses Gemini through OpenRouter. European hosting on every plan. Your data does not leave EU infrastructure and is never used to train shared models. @@ -125,7 +125,7 @@ Obligation detection scans your connected apps for things you have committed to: On Pro and Enterprise, Fluso runs your workload in a hardware-isolated environment so the model provider cannot read it. Useful when the work itself is sensitive. The technical details are on the [pricing page](https://fluso.ai/pricing.html). - SSO, audit logs, custom data retention, encrypted sandbox. SOC 2 Type II is in place. ISO 27001 is in progress. + Custom data retention and encrypted sandboxes are part of the Enterprise scope. Governance records persist the configured identity and access history, but Microsoft Entra metadata does not verify a directory or provide SSO by itself. Prem has attained SOC 2 Type I; Type II is underway. [Review the current security posture.](https://www.premai.io/security-at-prem) Custom skills are part of the Enterprise tier and are built with the Fluso team. For workspace-level skill creation on Plus and Pro, see [Skills](/features/skills). diff --git a/content/docs/resources/privacy.mdx b/content/docs/resources/privacy.mdx index d42521c..b5a62ad 100644 --- a/content/docs/resources/privacy.mdx +++ b/content/docs/resources/privacy.mdx @@ -60,8 +60,10 @@ Fluso uses a small set of vendors to operate the service. Each is bound by contr | Vendor | Purpose | |---|---| | Clerk | Authentication and user management. | -| Anthropic | Underlying LLM (anonymised; not used for training). | -| OpenAI | Underlying LLM (anonymised; not used for training). | +| Anthropic | Underlying LLM processing; not used for training. | +| OpenAI | Underlying LLM processing; not used for training. | +| OpenRouter | Model routing for Agent Studio. | +| Google | Gemini model processing for Agent Studio through OpenRouter. | | Stripe | Billing and payments. | | AWS | Infrastructure hosting. | @@ -99,11 +101,12 @@ The graph is the thing most worth understanding here, because it's the thing tha ## On Team plans -Admins can: +The current admin can: -- See which apps members have connected (for managing access). -- Set security policies. -- Manage user access and seat allocation. +- Store team membership, workspace roles, Agent access policies, access requests, and Microsoft Entra tenant metadata in the authenticated account's backend governance record. +- Review the identity and access changes recorded there. + +Directory verification and import, application inventory, seat controls, SSO, and runtime authorization enforcement require their owning Enterprise integrations. Admins cannot: @@ -111,11 +114,11 @@ Admins cannot: - Access members' personal knowledge graphs. - See content of a member's private projects. -Audit logs record administrative actions (seats added, policies changed) but not the content of any user's work. +The governance audit view records persisted identity and access changes, not the content of any user's work. It is scoped to the selected account and is not a complete organization-wide security log. ## Compliance -Fluso is built by Prem AI. For Enterprise customers we offer a Data Processing Agreement, custom data residency, audit logging, SSO (SAML/OIDC), and SOC 2 (in progress). +Fluso is built by Prem AI. Enterprise engagements can scope a Data Processing Agreement, custom data residency, broader server-backed audit logging, and SSO (SAML/OIDC). The current governance record is durable, but its Microsoft Entra metadata does not verify a directory or provide SSO by itself. Prem has attained SOC 2 Type I; Type II is underway. See the [current security posture](https://www.premai.io/security-at-prem). GDPR (EU/UK) and CCPA (California) data subject rights are honoured for all customers. Requests go to [privacy@premai.io](mailto:privacy@premai.io). diff --git a/content/docs/resources/security.mdx b/content/docs/resources/security.mdx index 82773e5..d21942e 100644 --- a/content/docs/resources/security.mdx +++ b/content/docs/resources/security.mdx @@ -13,10 +13,10 @@ This page is about the infrastructure side: how data is encrypted, how authentic | In transit | TLS 1.2+ on every connection | | Workspace files | Encrypted at rest (AES-256) | | Database | Encrypted at rest | -| OAuth tokens | Encrypted in a dedicated secrets manager | +| OAuth tokens | KMS-encrypted before storage in the backend database | | Conversations and chat history | Encrypted at rest | -OAuth tokens never appear in environment variables, logs, or anywhere outside the secrets manager. +OAuth tokens are encrypted before persistence and decrypted only by the backend paths that broker or refresh a connection. They are not exposed to the browser as stored credentials. ## Authentication @@ -32,9 +32,9 @@ OAuth tokens never appear in environment variables, logs, or anywhere outside th **Token refresh.** OAuth tokens are refreshed automatically before expiry. Failed refreshes show as a "Reconnect" option on the connection's row under **Plugins** instead of silent denial. -**Secret delivery.** Credentials reach containers via secure boot files, not environment variables. They cannot be enumerated by reading process state. +**Secret delivery.** Hosted runtime secrets use a one-time bootstrap payload: Docker receives it over stdin, while ECS uses an authenticated one-shot HTTP handoff. The payload is kept out of mounted files and the final process environment. -**Audit logging.** Administrative actions (account creation, OAuth grants, deletions) are logged. The content of your work is not. +**Governance audit logging.** Authenticated identity and access changes are stored in the backend governance record and shown in the admin audit view. This log covers the governance actions shown there; account-lifecycle, OAuth, and deletion auditing require their owning server integrations. Governance records do not contain the content of your work. ## Account security @@ -50,20 +50,19 @@ A few things to do, regardless of plan: ## What Fluso never does -The hard rules, encoded in the product itself: +Product controls and contractual commitments set these boundaries: -- Delete your emails or files. -- Change your account settings on connected apps. -- Take write actions on connected apps without your approval. -- Share your data with third parties. +- Operate outside the OAuth scopes granted to a connected app. +- Bypass the effective **Allow**, **Ask**, or **Deny** policy for a connected-app tool. +- Sell your data or disclose it outside contracted subprocessors. - Train models on your private data. - Access apps you haven't connected. -Most of these are technical impossibilities given the OAuth scopes Fluso requests. Some are policy commitments. All are tested. +OAuth scopes and tool policy enforce the connected-app boundaries. Contractual commitments apply where a technical control cannot express the boundary. ## Compliance -For Enterprise customers, Fluso supports custom data residency, SSO (SAML/OIDC), audit logging, SLA-backed availability, and a Data Processing Agreement. SOC 2 Type II audit is in progress. +Enterprise engagements can scope custom data residency, SSO (SAML/OIDC), broader server-backed audit logging, SLA-backed availability, and a Data Processing Agreement. The current Microsoft Entra configuration stores tenant metadata and governance history; it does not verify the directory or provide SSO by itself. Prem has attained SOC 2 Type I; Type II is underway. See the [current security posture](https://www.premai.io/security-at-prem). [Contact us](mailto:sales@premai.io) for the security questionnaire and detailed compliance documentation. diff --git a/content/docs/workflows/content-launch.mdx b/content/docs/workflows/content-launch.mdx index 008c5f8..a6dd311 100644 --- a/content/docs/workflows/content-launch.mdx +++ b/content/docs/workflows/content-launch.mdx @@ -36,7 +36,7 @@ A sequenced campaign instead of a single drop: A sales asset to match: -> *"Create a 10-slide sales demo deck for DataLens. Problem, solution, demo flow, customer proof, pricing, next steps. Modern design, brand colours."* +> *"Create a 10-slide sales deck for DataLens. Problem, solution, product walkthrough, customer proof, pricing, next steps. Modern design, brand colours."* A launch email to existing customers: diff --git a/content/docs/workflows/dev-bug-fix.mdx b/content/docs/workflows/dev-bug-fix.mdx index 91e59cc..7db3e6d 100644 --- a/content/docs/workflows/dev-bug-fix.mdx +++ b/content/docs/workflows/dev-bug-fix.mdx @@ -67,7 +67,7 @@ Always read the diff. Fluso writes good code, but you're still the engineer of r Drop a `context.md` in the repo describing your stack, conventions, and do-not-touch zones. Fluso reads and follows. The first PR after you add it will make the value obvious. - Fluso always asks for approval before opening a PR or pushing changes. You see the diff and decide. + Keep GitHub write tools on **Ask** to stop on each PR or push and review the diff. **Allow** or **Don't ask permission** can continue without a per-action prompt. ## Related