# What is briq
URL: https://briq.cloud/docs
> The services your agent's work needs, through one MCP server your agent signs in to.
briq gives any AI agent the services its work needs. The agent says "run `postgres:16`", briq
runs it on a microVM in Paris, returns a URL and credentials, and tears it down when the agent is
done.
It is not a code interpreter, a browser sandbox or a deployment platform.
## What you get
* **Any OCI image** from a public registry: `postgres:16`, `redis:7-alpine`,
`ghcr.io/you/api:sha-abc`.
* **Recipes**: ready-made stacks (`postgres`, `redis`, more in the [cookbook](https://briq.cloud/cookbook)) that
return connection strings.
* **One MCP server** at `https://api.briq.cloud/mcp`. Your client signs in through the browser, or
uses an API key where there is none. Works with Claude Code, Cursor, VS Code, Codex, Claude,
Gemini CLI and OpenCode.
* **Guardrails**: spend caps, concurrency limits, allowed sizes and registries per agent. Every
response carries `costCentsSoFar` and `sleepsAt`.
* **EU hosting**: Firecracker microVMs in Paris by default, or another [region](https://briq.cloud/docs/regions). One
private network per team.
* **Per-second billing**: briqs go to sleep when nothing uses them and wake on the next use, and a
sleeping briq is not billed. See [Cost](https://briq.cloud/docs/cost).
## Get started
Paste one prompt into your agent and it sets briq up itself: see the
[Quickstart](https://briq.cloud/docs/getting-started). To set up a client by hand, see [Clients](https://briq.cloud/docs/setup/clients).
## Next
* [Concepts](https://briq.cloud/docs/concepts/briq): briqs, stacks, recipes, agents, lifecycle.
* [Cost](https://briq.cloud/docs/cost): what a briq costs, and how the bill follows what runs.
* [MCP tools](https://briq.cloud/docs/mcp/tools): every tool, with an example.
* [Cookbook](https://briq.cloud/cookbook): every recipe, with params, outputs and calls.
* [Security](https://briq.cloud/docs/security): isolation, what briq stores, disclosure.
## For agents
Every page here and in the cookbook is also Markdown: add `.md` to its URL
([`/docs/concepts/fork.md`](https://briq.cloud/docs/concepts/fork.md)) or send `Accept: text/markdown`.
[`/llms.txt`](https://briq.cloud/llms.txt) indexes them; [`/llms-full.txt`](https://briq.cloud/llms-full.txt) is the whole site in one
file.
---
# Quickstart
URL: https://briq.cloud/docs/getting-started
> Connect your agent client to briq and run your first briq.
briq is one MCP server: `https://api.briq.cloud/mcp`. Your agent adds it to its own config; no account or key
needed first.
## Connect your agent
1. Paste this prompt into your agent:
```text
Add the briq MCP server to your config:
- name: "briq"
- url: https://api.briq.cloud/mcp (Streamable HTTP, OAuth)
- for all my projects
Then tell me what to do next to connect and activate it. If needed, read the setup instructions for agents: https://briq.cloud/docs/setup/agents.md
```
2. Follow your agent's next steps: usually a restart, then a link to sign in.
3. Try it:
- GitHub repo: "Run hextris/hextris github repo on briq (https://briq.cloud/docs/guides/run-a-github-repo.md) and give me a link to it."
- Reporting: "Start Metabase on briq (https://briq.cloud/cookbook/metabase.md), load 'Our World in Data' energy dataset into it, generate a report on world energy generation, and share it with me." (Metabase is an open-source BI tool, like Tableau.)
- Postgres: "Start a Postgres for this project on briq (https://briq.cloud/cookbook/postgres.md) and connect the app to it."
- Web app: "Run this app on briq (https://briq.cloud/cookbook/node.md) and give me a preview link."
- Memory: "Start a SiYuan notebook on briq (https://briq.cloud/cookbook/siyuan.md), keep your notes on this project in it, and give me a link to browse them." (SiYuan is an open-source notes app, like Obsidian.)
- Planning: "Start a Plane board on briq (https://briq.cloud/cookbook/plane.md), turn our TODO list into issues, and give me a link to the board." (Plane is an open-source project board, like Linear.)
The prompt gives your agent the server's name and URL; it knows how to add it to its own
config. To do it yourself, see [Clients](https://briq.cloud/docs/setup/clients).
## Sign in
Your agent tells you when. Usually it needs a restart, then your browser opens on the sign-in
step, or the first time it uses briq. Sign in (or create an account; Google and GitHub work) and
approve the client for a team, with its budget. The client keeps the sign-in; the model never
sees it.
An agent that runs elsewhere (on a server, or behind a chat app) cannot open your browser. It
sends you a link and a code instead: open the link on any device, check the code matches the one
it showed you, and approve.
The client then appears on the dashboard's **Agents** page, where you change its limits or revoke
it. See [Agents, keys and policy](https://briq.cloud/docs/concepts/keys-and-policy).
For CI, containers and scripts, create a key on the **Agents** page and send it as a Bearer
token: see [Clients](https://briq.cloud/docs/setup/clients#api-key). It works for the [REST API](https://briq.cloud/docs/api/overview) too.
## Your first briq
The client lists the `briq_*` tools and a `briq_getting_started` prompt. The tool descriptions
already tell the model how to use them; you do not need to write instructions.
Ask for something that needs a real service:
> Spin up a Postgres, apply the migrations in `db/migrations`, and tell me if they are clean.
```text
briq_run({ recipe: "postgres", params: { version: "16" } })
→ bq_7kq2m9x1p4ab db (postgres:16) running · …internal · cost so far … · sleeps at 18:42 UTC unless used
outputs:
DATABASE_URL=postgres://postgres:…@…internal:5432/app
briq_files_put({ briq: "bq_7kq2m9x1p4ab", path: "/m/001_init.sql", contentBase64: "…" })
briq_exec({ briq: "bq_7kq2m9x1p4ab", cmd: ["psql", "-U", "postgres", "-d", "app", "-v", "ON_ERROR_STOP=1", "-f", "/m/001_init.sql"] })
→ exit 0
CREATE TABLE
CREATE INDEX
briq_destroy({ briq: "bq_7kq2m9x1p4ab" })
→ bq_7kq2m9x1p4ab db (postgres:16) destroyed · …internal · cost so far …
```
* `briq_run` returns once the recipe's healthcheck passes, so the database is ready.
* Credentials are generated per run and returned once; they are masked in status, logs and audit.
* `DATABASE_URL` is a private address, reachable from briqs in your team, not from your machine.
Run commands with `briq_exec`, or run your code in a briq of the same
[stack](https://briq.cloud/docs/concepts/stack).
* If the agent forgets `briq_destroy`, the briq goes to sleep after an hour unused and costs
nothing until something uses it again.
## Watch it
The [dashboard](https://briq.cloud/app) shows running briqs, spend and the audit log (one row per call, with agent,
action, target and cost). Stop, change when it sleeps, or destroy anything from there.
## Without an agent
Every MCP tool is a [REST](https://briq.cloud/docs/api/overview) call:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" -H "Content-Type: application/json" \
-d '{ "recipe": "postgres", "wait": true }'
curl -X POST https://api.briq.cloud/v1/briqs/bq_7kq2m9x1p4ab/exec \
-H "Authorization: Bearer $BRIQ_API_KEY" -H "Content-Type: application/json" \
-d '{ "cmd": ["psql", "-U", "postgres", "-c", "select 1"] }'
curl -X DELETE https://api.briq.cloud/v1/briqs/bq_7kq2m9x1p4ab \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
---
# Clients
URL: https://briq.cloud/docs/setup/clients
> Add briq to your MCP client and sign in.
Add briq to your client by hand. Your agent can also do it for you: see the
[Quickstart](https://briq.cloud/docs/getting-started). Building your own agent? See [Frameworks](https://briq.cloud/docs/setup/frameworks).
Agent on a server or in a chat app? It signs in with a device code: see
[For agents](https://briq.cloud/docs/setup/agents#sign-your-person-in).
## Claude Code
1. Add briq:
```bash
claude mcp add --scope user --transport http briq https://api.briq.cloud/mcp
```
2. Sign in:
```bash
claude mcp login briq
```
Your browser opens to sign in.
Or run /mcp inside Claude Code and pick briq.
## Cursor
[Add to Cursor](cursor://anysphere.cursor-deeplink/mcp/install?name=briq&config=eyJ1cmwiOiJodHRwczovL2FwaS5icmlxLmNsb3VkL21jcCJ9)
Or add to ~/.cursor/mcp.json:
```json
{
"mcpServers": {
"briq": {
"url": "https://api.briq.cloud/mcp"
}
}
}
```
On first use, your browser opens to sign in.
## VS Code
[Install in VS Code](https://vscode.dev/redirect/mcp/install?name=briq&config=%7B%22type%22%3A%22http%22%2C%22url%22%3A%22https%3A%2F%2Fapi.briq.cloud%2Fmcp%22%7D)
Or add it for your user:
```bash
code --add-mcp '{"name":"briq","type":"http","url":"https://api.briq.cloud/mcp"}'
```
On first use, your browser opens to sign in.
## Codex
1. Add briq:
```bash
codex mcp add briq --url https://api.briq.cloud/mcp
```
2. Sign in:
```bash
codex mcp login briq
```
Your browser opens to sign in.
## Claude
In Claude (web or desktop): Settings → Connectors → Add custom connector.
Name it briq and paste this URL, then click Connect.
Remote MCP server URL:
```text
https://api.briq.cloud/mcp
```
Your browser opens to sign in.
## Gemini CLI
1. Add briq:
```bash
gemini mcp add --scope user --transport http briq https://api.briq.cloud/mcp
```
2. Sign in, inside Gemini CLI:
```bash
/mcp auth briq
```
Your browser opens to sign in.
## Antigravity
1. Add briq to ~/.gemini/config/mcp_config.json:
```json
{
"mcpServers": {
"briq": {
"serverUrl": "https://api.briq.cloud/mcp"
}
}
}
```
Then in Agent Settings → Customizations, click Authenticate next to briq.
Sign in, then paste the code back into Antigravity.
## OpenCode
1. Add briq to ~/.config/opencode/opencode.json:
```json
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"briq": {
"type": "remote",
"url": "https://api.briq.cloud/mcp",
"enabled": true
}
}
}
```
2. Sign in:
```bash
opencode mcp auth briq
```
Your browser opens to sign in.
## Hermes
1. Add briq to ~/.hermes/config.yaml:
```yaml
mcp_servers:
briq:
url: "https://api.briq.cloud/mcp"
auth: oauth
```
2. Sign in:
```bash
hermes mcp login briq
```
Or sign in on a server, or behind a chat app:
```bash
hermes mcp login briq --flow device
```
Your browser opens to sign in.
With --flow device, it prints a link and a code instead: open the link on any device, check the code and approve.
## OpenClaw
1. Add briq:
```bash
openclaw mcp set briq '{"url":"https://api.briq.cloud/mcp","transport":"streamable-http","auth":"oauth"}'
```
2. Sign in:
```bash
openclaw mcp login briq
```
Your browser opens to sign in.
On a server, sign in from the link it prints, then finish with the --code command it gives.
## Pi
Pi reaches MCP servers through the pi-mcp-adapter extension.
1. Install the MCP adapter:
```bash
pi install npm:pi-mcp-adapter
```
2. Add briq to ~/.config/mcp/mcp.json:
```json
{
"mcpServers": {
"briq": {
"url": "https://api.briq.cloud/mcp"
}
}
}
```
3. Sign in, inside Pi:
```bash
/mcp-auth briq
```
Your browser opens to sign in.
## Any MCP client
Any client that supports remote MCP servers (Streamable HTTP): add this URL.
MCP server URL:
```text
https://api.briq.cloud/mcp
```
Clients with MCP sign-in (OAuth) open your browser on first use.
Others can send an API key: see API key, below.
## API key
For CI, containers and scripts, where no browser can sign in.
Create a key on the Agents page, then send it as a Bearer token.
MCP: the URL, with the key in a header:
```json
{
"mcpServers": {
"briq": {
"url": "https://api.briq.cloud/mcp",
"headers": {
"Authorization": "Bearer ${BRIQ_API_KEY}"
}
}
}
}
```
Or call the REST API:
```bash
curl https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
How a client reads the key from the environment varies: see its docs.
---
# Frameworks
URL: https://briq.cloud/docs/setup/frameworks
> Connect an agent you build with an SDK to briq's MCP server, with an API key.
An agent you build with an SDK connects like any MCP client, with an API key instead of a
browser sign-in:
1. Create a key on the dashboard's **Agents** page, with the budget the agent may spend.
2. Keep it in `BRIQ_API_KEY`.
3. Point your framework at `https://api.briq.cloud/mcp` (Streamable HTTP), with the key as an
`Authorization: Bearer` header.
Each snippet below does step 3; replace `` with yours.
Using a coding agent or a chat app instead? See [Clients](https://briq.cloud/docs/setup/clients).
## Claude Agent SDK
`npm i @anthropic-ai/claude-agent-sdk` (or `pip install claude-agent-sdk`)
```ts
import { query } from '@anthropic-ai/claude-agent-sdk';
for await (const m of query({
prompt: 'Start a Postgres on briq',
options: {
mcpServers: {
briq: {
type: 'http',
url: 'https://api.briq.cloud/mcp',
headers: { Authorization: `Bearer ${process.env.BRIQ_API_KEY}` },
},
},
allowedTools: ['mcp__briq__*'],
},
})) if (m.type === 'result' && m.subtype === 'success') console.log(m.result);
```
`allowedTools` is what lets the agent call briq's tools without asking. A server that fails to
authenticate does not throw: it shows as `failed` or `needs-auth` in the init message.
## OpenAI Agents SDK
`pip install openai-agents` (or `npm i @openai/agents`)
```python
import os
from agents import Agent, Runner
from agents.mcp import MCPServerStreamableHttp
async with MCPServerStreamableHttp(
name="briq",
params={
"url": "https://api.briq.cloud/mcp",
"headers": {"Authorization": f"Bearer {os.environ['BRIQ_API_KEY']}"},
},
cache_tools_list=True,
) as briq:
agent = Agent(name="Ops", instructions="Use briq for services.", mcp_servers=[briq])
print((await Runner.run(agent, "Start a Postgres on briq")).final_output)
```
In JavaScript, `new MCPServerStreamableHttp({ name: 'briq', url, requestInit: { headers } })`,
then `await briq.connect()` before running the agent.
## Vercel AI SDK
`npm i ai @ai-sdk/mcp`
```ts
import { createMCPClient } from '@ai-sdk/mcp';
import { ToolLoopAgent } from 'ai';
const briq = await createMCPClient({
transport: {
type: 'http',
url: 'https://api.briq.cloud/mcp',
headers: { Authorization: `Bearer ${process.env.BRIQ_API_KEY}` },
},
});
try {
const agent = new ToolLoopAgent({ model: '', tools: await briq.tools() });
console.log((await agent.generate({ prompt: 'Start a Postgres on briq' })).text);
} finally {
await briq.close();
}
```
## LangChain and LangGraph
`pip install "langchain[mcp]"` (or `npm i langchain @langchain/mcp-adapters`)
```python
import os
from fastmcp.client import Client
from langchain.agents import create_agent
from langchain.mcp import MCPAdapter
async with MCPAdapter(Client("https://api.briq.cloud/mcp", auth=os.environ["BRIQ_API_KEY"])) as briq:
agent = create_agent("", await briq.list_tools())
await agent.ainvoke({"messages": [{"role": "user", "content": "Start a Postgres on briq"}]})
```
`auth=` sends the key as a Bearer token. In JavaScript:
`new MCPAdapter({ servers: { briq: { url, headers } } })`, then `await adapter.listTools()`. The
older `MultiServerMCPClient` from `langchain-mcp-adapters` still works with
`"transport": "http"` and `"headers"`.
## Mastra
`npm i @mastra/mcp @mastra/core`
```ts
import { Agent } from '@mastra/core/agent';
import { MCPClient } from '@mastra/mcp';
const mcp = new MCPClient({
servers: {
briq: {
url: new URL('https://api.briq.cloud/mcp'),
requestInit: { headers: { Authorization: `Bearer ${process.env.BRIQ_API_KEY}` } },
},
},
});
export const agent = new Agent({
id: 'ops',
name: 'Ops',
instructions: 'Use briq for services.',
model: '',
tools: await mcp.listTools(),
});
```
## Pydantic AI
`pip install "pydantic-ai-slim[mcp]"`
```python
import os
from pydantic_ai import Agent
from pydantic_ai.mcp import MCPToolset
briq = MCPToolset(
"https://api.briq.cloud/mcp",
headers={"Authorization": f"Bearer {os.environ['BRIQ_API_KEY']}"},
)
agent = Agent("", toolsets=[briq])
async def main():
async with agent:
print((await agent.run("Start a Postgres on briq")).output)
```
## Google ADK
`pip install google-adk`
```python
import os
from google.adk.agents import LlmAgent
from google.adk.tools.mcp_tool import McpToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
root_agent = LlmAgent(
model="",
name="ops",
instruction="Use briq for services.",
tools=[McpToolset(connection_params=StreamableHTTPConnectionParams(
url="https://api.briq.cloud/mcp",
headers={"Authorization": f"Bearer {os.environ['BRIQ_API_KEY']}"},
))],
)
```
## CrewAI
`pip install crewai mcp`
```python
import os
from crewai import Agent
from crewai.mcp import MCPServerHTTP
agent = Agent(
role="Ops",
goal="Run the services the crew needs",
backstory="Runs databases and apps on briq.",
mcps=[MCPServerHTTP(
url="https://api.briq.cloud/mcp",
headers={"Authorization": f"Bearer {os.environ['BRIQ_API_KEY']}"},
streamable=True,
)],
)
```
## Anything else
Any MCP client library works the same way: Streamable HTTP to the URL above, with the key in an
`Authorization: Bearer` header. Without MCP, every tool is also a [REST](https://briq.cloud/docs/api/overview) call.
---
# For agents
URL: https://briq.cloud/docs/setup/agents
> For an AI agent setting briq up for its person. Add the server, get them signed in, check it works.
This page is written for you, the agent someone asked to set up briq.
## Add the server
Add briq to your MCP config for all projects (user scope). Use the name and URL from the prompt you
were given; in production these are `briq` and `https://api.briq.cloud/mcp` (Streamable HTTP, OAuth).
If you do not know your client's exact syntax, its steps are on [Clients](https://briq.cloud/docs/setup/clients). Most
clients only see a new server after a restart: tell your person if yours needs one.
## Sign your person in
Signing in is your person's step: they pick the team you work for and your budget. You never
handle a password or a token; your client keeps the sign-in.
**Their browser can reach you** (you run on their computer). Start your client's sign-in
(`claude mcp login briq`, `codex mcp login briq`, `/mcp` and Authenticate…), or call any briq tool
and your client opens the browser.
**It cannot** (you run on a server, in a container, or answer in a chat app). Use your client's
device-code login: it prints a link and a code (Hermes: `hermes mcp login briq --flow device`).
Send your person the link, and the code if it is not in the link, like this:
> I've registered with briq; open this link to connect it to your account and get €10 of credits:
> [https://app.briq.cloud/connect?user\_code=ABCD-EFGH](https://app.briq.cloud/connect?user_code=ABCD-EFGH)
They check the code against the one you sent, then approve; your client picks up the sign-in by
itself. OpenClaw has no device-code login: your person signs in from the link it prints, and you
finish with the `--code` command it gives.
**Neither works.** Ask your person for an API key from the dashboard's **Agents** page, and send it
as `Authorization: Bearer ` (see [API key](https://briq.cloud/docs/setup/clients#api-key)). Keep it in an
environment variable, not in your conversation.
## Check it works
Call `briq_quota`: it answers with your team's plan, credits and limits. Then tell your person you
are ready.
## Start something useful
Do not stop at "it works". Look at the project you are in, and offer your person one first thing
to run on briq for it, ready to start on their yes:
| If the project has… | Offer to | Recipe |
| ------------------------------------------------- | ----------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------ |
| Migrations, a schema, an ORM | Start a Postgres, run the migrations against it, and say if they are clean | [postgres](https://briq.cloud/cookbook/postgres) |
| A web app (Node, Python, Go…) | Run it with what it needs (a database, a cache) and share a preview link | [node](https://briq.cloud/cookbook/node), [python](https://briq.cloud/cookbook/python), [static](https://briq.cloud/cookbook/static) |
| Background jobs or a queue | Start a Redis next to it and run the workers | [redis](https://briq.cloud/cookbook/redis) |
| Tests that need real services | Run the suite against real ones instead of mocks | [Guide](https://briq.cloud/docs/guides/run-tests-against-real-services) |
| Notes, decisions, a TODO list | Keep them in a notebook (SiYuan) or a board (Plane) you both can open | [siyuan](https://briq.cloud/cookbook/siyuan), [plane](https://briq.cloud/cookbook/plane) |
| Data: CSV files, exports, a database to report on | Load it into a Postgres and build a Metabase dashboard (like Tableau) they can open from a link | [metabase](https://briq.cloud/cookbook/metabase) |
Nothing to go on (an empty folder, a chat)? Ask what they are working on, or offer something
useful on its own: the notebook, or a dashboard of where the world's electricity comes from, built
from Our World in Data's open energy dataset in a few minutes
([Guide](https://briq.cloud/docs/guides/report-on-a-dataset)).
`briq_catalog` lists every recipe.
## Troubleshooting
**The briq tools do not show up.** A client loads its MCP servers when it starts: restart it, or
reconnect the server (`/mcp` in Claude Code).
**The sign-in never finishes.** Your person's browser cannot reach you: use the device-code login
above, or an API key.
**Calls fail with `invalid_token`.** An access token lasts 30 days. Your client renews it with
the refresh token it received at sign-in, without your person; if it kept none, sign in again. A
refresh token works once: when several of your processes share one, the first to refresh must
save the new one where the others read it, or they are all signed out. You are also signed out
when you are revoked on the dashboard's **Agents** page, or after 30 days without a call.
**Sign-in calls fail with `429`.** Too many requests from your address, for example several
processes polling one device code at once. The answer says how long to wait (`Retry-After`, and
`retry_after_seconds` in the body): wait that long, from one process, and keep using the same
device code while it is valid (15 minutes) instead of asking for a new one.
**Calls fail with `payment_required`.** The team has no credits. Your person confirms their email
address (that unlocks the free credits) or tops up on the dashboard. Retrying does not help.
## Tell us what is wrong
When briq does not do what these docs say, fails with an error you cannot explain, or is missing
something you needed, send it to the people who build briq with `briq_feedback` (`bug`, `idea` or
`question`). Ideas are welcome too. Write it so it stands alone: what you did, what you expected,
what happened, the briq id and request id. Leave out secrets and your person's data, and tell your
person what you sent: they get a copy and the answer by email.
## More
* [MCP tools](https://briq.cloud/docs/mcp/tools): every tool, with an example.
* [Cookbook](https://briq.cloud/cookbook): every recipe, with its parameters and outputs.
* [Agents, keys and policy](https://briq.cloud/docs/concepts/keys-and-policy): what your budget limits.
* [Cost](https://briq.cloud/docs/cost): what a briq costs.
---
# Briq
URL: https://briq.cloud/docs/concepts/briq
> One running OCI image on its own microVM.
A **briq** is one OCI image running on its own microVM, with an internal address, optional ports
and volume, a size, and a sleep window.
## Fields
| Field | Notes |
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `id` | `bq_` and 12 characters, e.g. `bq_7kq2m9x1p4ab` |
| `stackId`, `name` | Name: lowercase, digits and dashes, up to 32 characters, unique in its [stack](https://briq.cloud/docs/concepts/stack) |
| `image` | Any public OCI reference allowed by the agent's policy |
| `cmd`, `entrypoint`, `env`, `ports` | As in a container spec. An `env` value is a string, `{ secret: NAME }` for a generated, write-only secret, or `{ secret: NAME, value }` for a credential you already have, stored encrypted and never shown again. Plain values show in status and the dashboard: a credential always goes as a secret |
| `size` | `nano`, `small`, `medium` or `large`. See [Cost](https://briq.cloud/docs/cost) |
| `files` | Written before the process starts, and whenever it starts over. See [Files](#files) |
| `state` | `running`, `sleeping`, `stopped`… See [Lifecycle](https://briq.cloud/docs/concepts/lifecycle-and-sleep#states) |
| `stoppedReason`, `lastExit` | Why a stopped or sleeping briq is not running; how its process last exited. See [When the process exits](https://briq.cloud/docs/concepts/lifecycle-and-sleep#when-the-process-exits) |
| `internalHost` | Reachable from any briq in the team |
| `endpoints` | Its URL, once published (`expose` on `briq_run`, or `briq_expose`), and its TCP endpoints (`briq_expose` with a `protocol`) |
| `databasePorts` | Its recipe's database ports and their protocol: what to pass `briq_expose` |
| `sleep`, `sleepsAt` | Sleeps after this long unused: `"30m"`, `"3h"`, `"7d"` or `"never"`, a string. Default `"1h"` on briq.cloud. `sleepsAt`: when, unless used first. See [Sleep](https://briq.cloud/docs/concepts/lifecycle-and-sleep#sleep) |
| `startedAt` | When its current run started: how long it has been awake |
| `costCentsSoFar` | Metered per second while it runs |
## A briq spec
What a recipe renders. Over REST, send your own as `spec` to `POST /v1/briqs`. `briq_run` takes
every field but `expose`, plus `expose: "public" | "private"` to publish the briq's single port.
```json
{
"name": "db",
"image": "postgres:16",
"env": { "POSTGRES_PASSWORD": { "secret": "POSTGRES_PASSWORD" }, "POSTGRES_DB": "app" },
"ports": [5432],
"size": "small",
"volume": { "mount": "/var/lib/postgresql/data", "gb": 2 },
"healthcheck": { "cmd": ["pg_isready", "-U", "postgres"] },
"sleep": "1h"
}
```
With a `healthcheck`, the briq is `running` only once the command succeeds. Without one, `running`
means the process started: if it exits a moment later, the briq stops and its status says how (see
[Lifecycle](https://briq.cloud/docs/concepts/lifecycle-and-sleep#when-the-process-exits)).
A probe should ask `127.0.0.1`, not `localhost`: inside a briq, `localhost` is `::1`, which a server
listening on IPv4 only refuses.
## Files
`files` puts files in place before the process starts: your app's sources, a config file. Text
goes as it is, binary as `{ "base64": "…" }` (padded, on one line; base64 whose length shows it
was cut short is refused); 256 KB in all.
```json
{
"name": "web",
"image": "python:3.12-slim",
"files": { "/app/server.py": "from http.server import …" },
"cmd": ["python", "/app/server.py"],
"ports": [8080]
}
```
They are written again whenever the process starts over (a restart, a cold start), so the spec
stays their source of truth: an edit made inside the briq to one of them lasts until then. A
resume from a memory snapshot (`nano` and `small` sizes) is not a start over: the process carries
on where it was, files included. A fork gets them too. For anything
bigger, fetch it from inside the briq (`git clone`, `curl`).
* Paths are absolute, without `.` or `..` segments: `/app/server.py`, not `server.py`.
* 64 files and 256 KB in all.
* Status lists them by path and size; their content is not shown again, and the audit log
records the path and size only.
* `briq_files_put` on one of them answers with a warning: the change lasts until the next start.
## Disk
A briq keeps its disk. Files written anywhere in it, by its process, `briq_exec` or
`briq_files_put`, are still there after a stop, a start, a restart or an expose. A destroy removes
them.
A `volume` is the durable part: use one for data you cannot afford to lose, such as a database's
files. Its size is `gb`, 2 by default and up to 500, set at creation and counted toward your
[plan's disk](https://briq.cloud/docs/cost#plans); a recipe takes it as `diskGb`. The rest of the disk can be reset
to the image during the provider's host maintenance, and a [fork](https://briq.cloud/docs/concepts/fork) copies the
volume only.
## What a briq is not
* Not a container on a shared kernel: each briq is a Firecracker microVM.
* Not a place for data you cannot lose outside a `volume`, and nothing survives a destroy.
* Not reachable from the internet until you publish it (`expose` on `briq_run`, or
`briq_expose`).
---
# Stack
URL: https://briq.cloud/docs/concepts/stack
> A named group of briqs that can talk to each other.
A **stack** groups briqs inside a team. Briqs in a stack find each other by name, which is how a
multi-briq recipe (Redis and its dashboard, an app and its database) wires itself up.
## Using one
`briq_run` uses the stack `default` unless you pass `stack`, and creates the stack on first use:
```text
briq_run({ recipe: "postgres", stack: "checkout" })
briq_run({ recipe: "redis", stack: "checkout" })
briq_run({ image: "ghcr.io/acme/checkout-api:pr-412", stack: "checkout", ports: [3000],
env: { REDIS_HOST: "{{briq:redis}}" } })
```
## Reaching another briq
* **Recipe outputs** already carry the right address: pass `DATABASE_URL` to another briq as is.
* **`{{briq:}}`** in an `env` value becomes the address of the briq with that name in the
same stack. The briq waits for it to be running before it starts. It works in plain values, not
inside a secret's `value`: put the address in a plain variable and the password in a secret.
These addresses only resolve inside the team's network. From outside, use `briq_exec`, or
`briq_expose` an HTTP port.
## Isolation
The tenant boundary is the **team**: one private network per team, never shared with another
customer. A stack is not a security boundary: any briq can reach any other briq of the same team.
---
# Recipes
URL: https://briq.cloud/docs/concepts/recipes
> Ready-made stacks that return connection strings, not Dockerfiles.
A **recipe** is a ready-made stack your agent asks for by name. It starts one or more briqs, waits
until they are healthy, and returns **outputs**: the connection strings and credentials your code
needs. Every recipe has a page in the [cookbook](https://briq.cloud/cookbook).
```text
briq_run({ recipe: "postgres" })
→ bq_7kq2m9x1p4ab db (postgres:16) running · …internal · cost so far … · sleeps at 18:42 UTC unless used
outputs:
DATABASE_URL=postgres://postgres:…@…internal:5432/app
PGHOST=…internal
PGPORT=5432
…
```
* **Parameters** all have defaults, so the bare name always works. Pass them to change what you
get: `params: { version: "17", extensions: ["pgvector"] }`.
* **Disk**: every recipe that keeps data takes `diskGb`, its volume's size. Defaults are small
(1 to 5 GB); ask for what the data needs when you create it, `params: { diskGb: 20 }`, since the
size is set then and counts toward your [plan's disk](https://briq.cloud/docs/cost#plans).
* **Secrets** are generated per run, returned once, and masked in status, logs and audit.
* **Outputs** are private addresses: they work as is from any briq in the team (use `briq_exec`,
or run your code in a briq of the same [stack](https://briq.cloud/docs/concepts/stack)), not from outside.
* **`expose`** (`"private"`, or `"public"` for anyone) publishes the recipe's front door, when it has
one (a dashboard, a wiki), and adds `URL` to the outputs. Databases have none, and asking fails.
Over REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" -H "Content-Type: application/json" \
-d '{ "recipe": "postgres", "params": { "version": "17" } }'
```
`briq_catalog` (or `GET /v1/recipes`) lists every recipe; with a name (`GET /v1/recipes/{name}`),
every parameter it takes, with its default and what it does, and its outputs.
## Recipe or image?
Use a recipe when one fits: you get the healthcheck, credentials and connection strings for free.
Your own code runs on a [language recipe](https://briq.cloud/docs/guides/run-your-own-app), with no image to build.
Otherwise pass any image to `briq_run` with its own `env`, `ports`, `files`, `volume` and
`healthcheck` ([spec](https://briq.cloud/docs/concepts/briq#a-briq-spec)).
---
# Agents, keys and policy
URL: https://briq.cloud/docs/concepts/keys-and-policy
> What an agent can do, how it signs in, and who sets its policy.
An **agent** is anything that calls briq for a team. The dashboard's **Agents** page lists them,
and each has a **policy**, checked before any machine is created. Two kinds, treated the same:
| | Connected client | API key |
| ------ | ---------------------------------------------------------------------------------- | -------------------------------------------------------------------- |
| For | A client on a machine with a browser: Claude Code, Cursor, VS Code, Codex, Claude… | CI, containers, scripts, the REST API |
| How | Add the MCP URL; the client signs in through your browser and you approve it | Create it on the Agents page, send `Authorization: Bearer bq_live_…` |
| Secret | Tokens the client keeps and refreshes; never shown to the model | The key, shown once |
| Policy | Set on the approval page | Set at creation |
Both are editable and revocable on the Agents page; revoking takes effect immediately. A connected
client lasts as long as the person who approved it stays in the team.
Each agent shows the client that last used it (Claude Code 2.1.278, Cursor, curl 8.7.1), and the
audit log records it on every row.
## The policy
| Field | Default | Effect |
| -------------------- | --------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `maxConcurrentBriqs` | `5` | Live briqs the agent may have at once |
| `dailySpendCapCents` | `1000` | Daily spend. Checked before create; the agent's briqs stop when it is crossed, and sleep again from the next UTC day |
| `allowedSizes` | `nano`, `small` | The team's [plan](https://briq.cloud/docs/cost#plans) must allow them too |
| `allowedRegistries` | `docker.io`, `ghcr.io`, `quay.io` | Image hosts allowed (`docker.io` covers unqualified images) |
| `maxSleep` | `"never"` | The longest [`sleep`](https://briq.cloud/docs/concepts/lifecycle-and-sleep#sleep) the agent may give a briq, as a string (`"1d"`). `"never"` sets no bound of its own: the environment's longest window and the plan (always on is Pro and above) still apply |
| `expiresAt` | none | The agent is rejected after this time |
A key is the team's: it sees and acts on everything in the team, every briq, stack, endpoint,
the audit log, the list of keys and agents, under the budget its policy sets. The policy bounds
what the key spends, not what it reaches; for a narrower reach, make a separate team. The one
thing a key never does is manage credentials: only a person signed in to the dashboard creates,
edits or revokes keys and connected clients, and an API key calling those routes gets
`403 forbidden`. So an agent cannot raise its own budget, mint itself a wider key, or cut off the
team's other agents. A policy is also bounded by the plan of the person setting it
(`402 policy_violation` past it), and it applies to a start as to a create: a key capped at one
briq cannot keep restarting others. Keys outlive the person who created them: removing a member
keeps the team's keys and lists the ones they created, for the team to rotate if it wants to. See
[Budgets](https://briq.cloud/docs/guides/budgets).
Each key and each connected client is one of the team's agents; the
[plan](https://briq.cloud/docs/cost#plans) sets how many a team may have.
## Errors
| Code | HTTP | When |
| ------------------ | ---- | ------------------------------------------------------------------------------------------------------ |
| `policy_violation` | 402 | Size, registry or `sleep` not allowed. The message says the longest `sleep` to send |
| `quota_exceeded` | 402 | Concurrency limit or daily cap reached |
| `payment_required` | 402 | The team is out of credits |
| `plan_limit` | 403 | The team's plan does not allow it: a size, more disk, an always-on briq, another agent, another member |
Over MCP the same message comes back as a tool error. `briq_quota` (or `GET /v1/quota`) reports
what is left, so a model can plan instead of retrying.
---
# Lifecycle and sleep
URL: https://briq.cloud/docs/concepts/lifecycle-and-sleep
> States, moves, and the one setting that decides when a briq stops on its own.
## States
```text
creating → running → stopping → stopped → starting → running
running → stopping → sleeping → starting → running
stopped by a limit → sleeping, once the limit clears
any live state → destroying → destroyed
a failed move → error
```
| State | Meaning | Billed |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------ |
| `creating` | Image pulling, healthcheck pending | No |
| `running` | Healthcheck passed, or the process is up | Yes |
| `stopping` | Stop on its way | Yes |
| `sleeping` | Machine stopped, disk kept. The next call or visit wakes it | No |
| `stopped` | Machine stopped, disk kept: by `briq_stop`, by its process exiting, or by a limit not yet cleared. See [Other stops](#other-stops) | No |
| `starting` | Start on its way | No |
| `destroying`, `destroyed` | Machine and disk removed | No |
| `error` | The create failed: an image, a healthcheck that never passed, a process that exited before it was ready, or the infrastructure. Reason in `error`. Destroyed automatically after 7 days (`destroysAt`); its logs are readable until then | No |
`briq_stop`, `briq_start` and `briq_destroy` return once the move lands (up to 30 seconds), or with
the pending state. They are safe to repeat: stopping a stopped briq returns its state, and asking
again while a move is in flight waits for it. A destroy overtakes any move in flight. Impossible
moves, like starting a destroyed briq, return `invalid_state` (409).
Moves run in the background: if your client disconnects, the briq is still tracked, still put to
sleep on time, and the move completes.
## Sleep
Every briq has one setting that decides when it stops on its own: `sleep`. After that long without
use, the briq goes to sleep. A sleeping briq keeps its disk and is not billed for compute, and the
next use wakes it.
| `sleep` | The briq |
| ------------------------------ | -------------------------------------------------------------------------------------------------------- |
| `"1h"` (default on briq.cloud) | sleeps after 1 hour without use |
| `"30m"`, `"3h"`, `"7d"` | sleeps after that long without use: 5 minutes to 7 days |
| `"never"` | is always on: it runs until someone stops it, its process exits, or a limit stops it. Pro plan and above |
Nothing is deleted because of time. A sleeping briq is still there tomorrow and next month, with
its data, until you `briq_destroy` it.
### The `sleep` value
A string: a whole number and a unit (`m` for minutes, `h` for hours, `d` for days), or `"never"`.
Never a number. A call that sends one is refused, with the string to send instead:
```text
sleep must be a string: "30m", "3h", "7d" or "never". You sent 30, a number. For 30 minutes, pass "30m"
```
Responses show the shortest exact form: `"120m"` comes back as `"2h"`. Every response about a
running briq carries `sleepsAt`, the time it goes to sleep unless it is used before then. Every
use moves it later, so read it as a time, not a deadline. It is `null` while the briq is not
running, and for an always-on briq.
### What counts as use
* Your calls on any briq of its stack: `briq_exec`, the file tools, `briq_logs`, `briq_expose`.
Working on an app is using the database behind it too.
* Requests to the URL of any briq in its stack. A request to a [private URL](https://briq.cloud/docs/guides/expose-a-preview-url)
counts only when it carries the URL's token.
* On the dashboard, running a command. Watching a briq's page or its logs does not count.
Work that happens only inside the briq is not seen: a long job, a worker reading a queue, a bot
that only opens outgoing connections. Give such a briq a `sleep` longer than that work, or
`"never"`.
### Waking up
The next call that needs the briq running (an exec, a file read or write, an expose) wakes it
first, and the sleeping briqs of its stack with it, each under the agent's own limits (a sibling
past them stays asleep). The agent sees a slower call, not an error. A
visit to its URL wakes the whole stack and waits for it. `nano` and `small` resume from a memory
snapshot in about a second; larger sizes start from scratch, and the first visitor waits a few
seconds.
### Changing it
Pass `sleep` to `briq_run` (with a recipe, every briq it makes gets the same), to `briq_fork`, or
call `briq_set_sleep` on an existing briq:
```text
briq_set_sleep({ briq: "bq_7kq2m9x1p4ab", sleep: "3h" })
briq_set_sleep({ briq: "bq_7kq2m9x1p4ab", sleep: "1d", stack: true })
```
A running briq sleeps the new window from now. A sleeping briq stays asleep: the window applies
from its next wake. With `stack: true`, every briq of its stack gets the same.
### Limits
A window must be one the environment and the agent's key allow:
* The longest window is 7 days on briq.cloud.
* A key can set a shorter longest window (`maxSleep`, see [Keys and policy](https://briq.cloud/docs/concepts/keys-and-policy)).
* `"never"` needs the Pro plan or above. A team that moves down keeps the always-on briqs it has;
only new ones are refused.
A longer window is refused, never shortened behind your back, and the error says what to send:
```text
this fork would sleep after "3d", longer than this key allows ("1d"); pass sleep: "1d" or shorter
```
A fork keeps its source's `sleep` unless you pass one, so a fork made by a key with a shorter
longest window is refused the same way.
### Example: a site that stays reachable for a month
```text
briq_run({ recipe: "node", params: { files: … }, expose: "public", sleep: "30m" })
```
With no visits for 30 minutes it sleeps, and the next visit wakes it. It costs nothing while it
sleeps, and stays reachable for as long as you keep it.
## Other stops
A briq also stops when:
| `stoppedReason` | What stopped it | What brings it back |
| --------------- | ------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| `cap` | Its key's daily spend cap | From the next UTC day, or once the cap is raised, it is asleep: the next use wakes it |
| `credits` | The team ran out of credits | Once the team tops up (or pays as it goes), it is asleep: the next use wakes it |
| `user` | `briq_stop`, also on a sleeping briq: visits then no longer wake it | `briq_start` |
| `exited` | Its own process ending | `briq_start` (see below) |
Until then, a call that needs the briq running fails: `quota_exceeded` (402) for the cap,
`payment_required` (402) for credits, `invalid_state` (409) after a stop or an exit. Its URL
answers 503. A briq the provider stopped on its own (`provider`) is asleep, like an unused one.
The spend cap and the credits are what bound a briq in use: a briq is never stopped while it is
in use because a timer ran out. Briqs made from the dashboard have a daily cap too.
## When the process exits
A briq runs one long-lived process: the image's command, or your `cmd`. When it exits (a crash, a
missing file, a command that simply finishes), the briq stops with `stoppedReason: "exited"`; a
process that failed (a non-zero exit code) is first restarted up to three times. Its status carries `lastExit`: the exit code, the
time, and whether it ran out of memory. `briq_logs` shows what it printed.
An exited briq does not come back on the next call or visit, since that would only repeat the
exit: calls return `invalid_state` with the exit code. `briq_start` runs the same command and files
again, which is right when the cause was outside it (a dependency that was down, a spike that ran
it out of memory). A briq's command, files and size cannot be changed in place: to change them,
run a new briq with the fix and `briq_destroy` this one. The usual cause is a command that needs
files the briq does not have, such as your app's code: pass those in the spec's
[`files`](https://briq.cloud/docs/concepts/briq#files), written before the process starts.
A process that exits before the briq is ready (before its healthcheck passes) fails the create
instead: the briq is in `error`, and `error` says how the process exited.
A process that is still up when its healthcheck's `timeoutMs` runs out is a slow boot, not a
failure: the briq stays `creating` and the create waits for the healthcheck again, up to three
times in all. Meanwhile `error` says it is still starting. Only then does the create fail.
## A long time awake
A briq awake for 7 days in a row is marked in `briq_list` and on the dashboard ("awake for 8
days"). It is always on, or something keeps using it: often an uptime check or a crawler on a
public URL. It changes nothing about the briq; it is there so that a briq nobody is watching does
not run unseen.
## Forks
[`briq_fork`](https://briq.cloud/docs/concepts/fork) creates a new briq from a copy of a running, sleeping or stopped
briq's volume, with its own lifecycle. A briq mid-move cannot be forked until the move lands.
---
# Forks
URL: https://briq.cloud/docs/concepts/fork
> Branch a briq, or a whole stack, before a change you might want to undo.
A fork is a new briq that starts from a copy of another briq's volume. The source keeps running and
never sees what the fork does. Keep the fork, or destroy it to throw the attempt away.
Use it to try what cannot be taken back (run a migration on a fork first), or to try two approaches
side by side.
```text
briq_fork({ briq: "bq_7kq2m9x1p4ab" })
→ forked into stack default · copied disk: processes start fresh on a copy of the source volume as of now
bq_3m1x8kq2c7ta db-fork (postgres:16) running · fork of bq_7kq2m9x1p4ab · …internal · cost so far … · sleeps at 18:42 UTC unless used
outputs:
DATABASE_URL=postgres://postgres:…@…internal:5432/app
```
## What is copied
Each fork reports what it got in `copied`:
| `copied` | The fork gets | When |
| -------- | ---------------------------------------------------- | ---------------------------------------------------- |
| `disk` | The volume as it was at the fork | The source has a volume (every database recipe does) |
| `config` | Image, command, env, secrets and boot files, no data | The source has no volume |
Memory is not copied: processes start fresh on the copied disk, as after a power cut, and
databases recover as they are built to. For a clean copy, `briq_stop` the source first.
Not copied: its URL (expose the fork yourself), files written outside the volume (boot files
are config, and copied), and any link between the two. Destroying one leaves the other running.
A fork keeps its source's secrets (a database keeps the password it was created with). Its outputs
point at the fork.
## Names and stacks
| You pass | The fork is |
| --------------- | ------------------------------------------------------------------ |
| `briq` | `-fork` in the same stack (then `-fork-2`, …) |
| `briq`, `name` | That name, in the same stack |
| `briq`, `stack` | The source's name, in that stack |
| `stack` | Every briq of the stack, same names, in `-fork` (or `into`) |
Because names are kept, a forked app talks to the forked database with no configuration change:
```text
briq_fork({ stack: "shop", into: "shop-migration" })
→ forked into stack shop-migration · copied disk: …; config only: …
bq_… db running · fork of bq_…
bq_… api running · fork of bq_…
```
A briq that refers to a sibling (`{{briq:redis}}`) cannot be forked alone into a stack without a
briq of that name.
A stack fork is all or nothing: if one fork is refused, the others are destroyed and the call fails.
Briqs in `error` are left out and listed in `skipped`.
## Limits and cost
A fork is a new briq: it counts against the agent's policy and the team's credits, checked before
anything is copied, and bills per second. It runs in its source's region. A briq mid-move returns
`invalid_state` until the move lands.
## REST
```bash
curl -X POST https://api.briq.cloud/v1/briqs/bq_7kq2m9x1p4ab/fork \
-H "Authorization: Bearer $BRIQ_API_KEY" -H "Content-Type: application/json" -d '{}'
curl -X POST https://api.briq.cloud/v1/stacks/shop/fork \
-H "Authorization: Bearer $BRIQ_API_KEY" -H "Content-Type: application/json" \
-d '{ "into": "shop-migration" }'
```
Both answer like `POST /v1/briqs`, with `copied` and `skipped` added.
---
# Give Claude Code a database
URL: https://briq.cloud/docs/guides/give-claude-code-a-database
> Let the agent run migrations, seed data and test queries against a real Postgres.
Recipe:
- [PostgreSQL](https://briq.cloud/cookbook/postgres.md): A PostgreSQL database with a persistent volume. Optional pgvector.
Your project has Prisma, Drizzle or SQL migrations, and you want the agent to check them against a
real database instead of reasoning about them.
## Setup
Connect Claude Code to briq once: see the [Quickstart](https://briq.cloud/docs/getting-started).
Optionally, state your preferences in `CLAUDE.md`:
```md
## Databases
Use the briq MCP server for any Postgres you need: the `postgres` recipe, and destroy the briq
when you are done.
```
## Ask
> Apply our migrations to a fresh Postgres 17 with pgvector and check the schema.
The database is on briq's private network, so the agent works inside it. SQL migrations (Prisma
and Drizzle both write them) go straight to `psql` in the database briq:
```text
briq_run({ recipe: "postgres", params: { version: "17", extensions: ["pgvector"] } })
→ bq_7kq2m9x1p4ab db (pgvector/pgvector:pg17) running · …internal · cost so far … · sleeps at 18:42 UTC unless used
outputs:
DATABASE_URL=postgres://postgres:…@…internal:5432/app
briq_files_put({ briq: "bq_7kq2m9x1p4ab", path: "/m/001.sql", contentBase64: "…" })
briq_exec({ briq: "bq_7kq2m9x1p4ab", cmd: ["psql", "-U", "postgres", "-d", "app", "-v", "ON_ERROR_STOP=1", "-f", "/m/001.sql"] })
briq_exec({ briq: "bq_7kq2m9x1p4ab", cmd: ["psql", "-U", "postgres", "-d", "app", "-c", "\\dt"] })
briq_destroy({ briq: "bq_7kq2m9x1p4ab" })
```
When the tool must run your code (`prisma migrate deploy`, `prisma db seed`), run it from a
`node:22` briq in the same stack with the outputs as env; see
[Run tests against real services](https://briq.cloud/docs/guides/run-tests-against-real-services#run-in-briq).
## Tips
* **Keep it while iterating.** An unused briq goes to sleep on its own, and the next call wakes it
with its data. Destroy it at the end.
* **Seed from a dump**: `briq_files_put` it, then `psql -f`.
* **Name the stack** (`stack: "acme-dev"`) when the agent runs several services.
* **Cap the agent** with a [budget](https://briq.cloud/docs/guides/budgets): a runaway loop then costs the cap you
set, not a weekend.
---
# Run your own app
URL: https://briq.cloud/docs/guides/run-your-own-app
> Your code as a running service, with a URL, in one call and no image to build.
Recipes:
- [Python app](https://briq.cloud/cookbook/python.md): Your Python code running as a service, from files or a GitHub repo: it installs requirements.txt and starts it. No image to build.
- [Node.js app](https://briq.cloud/cookbook/node.md): Your Node.js code running as a service, from files or a GitHub repo: it installs package.json and starts it. No image to build.
- [Bun app](https://briq.cloud/cookbook/bun.md): Your TypeScript or JavaScript running on Bun, from files or a GitHub repo: it installs package.json and starts it. No build step.
- [Go app](https://briq.cloud/cookbook/go.md): Your Go code running as a service, from files or a GitHub repo: it builds the module and starts the binary. No image to build.
- [Ruby app](https://briq.cloud/cookbook/ruby.md): Your Ruby code running as a service, from files or a GitHub repo: it bundles the Gemfile and starts it. No image to build.
- [Rust app](https://briq.cloud/cookbook/rust.md): Your Rust crate running as a service, from files or a GitHub repo: it builds a release and runs it. No image to build.
- [PHP app](https://briq.cloud/cookbook/php.md): Your PHP code served by PHP's built-in server, from files or a GitHub repo. No image to build.
- [Static site](https://briq.cloud/cookbook/static.md): HTML, CSS, JavaScript and images served by nginx, from files or a folder of a GitHub repo. No build, no image.
An agent writes a small app (an API, a dashboard, a webhook receiver) and wants it running where
someone can open it. A language recipe takes the code as files and runs it: no Dockerfile, no
registry, no build to wait for on your side.
On GitHub, GitLab or another git host: see [Run a GitHub repo](https://briq.cloud/docs/guides/run-a-github-repo). The
briq downloads the code itself.
## Pick your language
| Recipe | Image | Installs at each start | Starts with |
| -------------------------- | ------------------------- | ---------------------- | ------------------------- |
| [python](https://briq.cloud/cookbook/python) | `python:-slim` | `requirements.txt` | `python app.py` |
| [node](https://briq.cloud/cookbook/node) | `node:-slim` | `package.json` | `node server.js` |
| [bun](https://briq.cloud/cookbook/bun) | `oven/bun:1-slim` | `package.json` | `bun run server.ts` |
| [go](https://briq.cloud/cookbook/go) | `golang:-alpine` | builds the module | the binary |
| [rust](https://briq.cloud/cookbook/rust) | `rust:1-slim` | builds a release | `cargo run --release` |
| [ruby](https://briq.cloud/cookbook/ruby) | `ruby:-slim` | `Gemfile` | `ruby app.rb` |
| [php](https://briq.cloud/cookbook/php) | `php:-cli` | nothing | PHP's built-in server |
| [static](https://briq.cloud/cookbook/static) | `nginx` | nothing | nginx, serving your files |
Each takes `version`, `files` (your code), `start`, `install` and `build` to change the defaults,
`env`, `port` (8080) and `size`. Python, node, bun and ruby also take `packages`, for dependencies
without a manifest. `static` takes only `files` and `size`, and serves port 80. Without `files`,
each runs a hello-world app, a quick way to see the shape of it.
## One call
```text
briq_run({
recipe: "python",
params: {
files: {
"app.py": "…a Flask app listening on :: and $PORT…",
"requirements.txt": "flask"
}
},
expose: "private"
})
→ bq_9a2… app (python:3.12-slim) running · …internal · url: https://app-m4qa.briq.run/?briq_token=… · cost so far … · sleeps at 18:42 UTC unless used
outputs:
APP_URL=http://…internal:8080
URL=https://app-m4qa.briq.run/?briq_token=…
```
What happens:
1. The files are written into the briq under `/app` **before** anything starts.
2. `requirements.txt` is installed, then `python app.py` starts with `PORT=8080`.
3. briq waits until something answers on that port, then the call returns. A first install or
build can outlast the call's two minutes: the briq then shows `creating`, and `briq_status`
tells you when it runs.
4. The URL was published as the briq was created: nothing restarts to publish it, and with
`wait: false` you get it at once.
## With a database
Run the database first, in the same stack, and hand its connection string to the app:
```text
briq_run({ recipe: "postgres", stack: "portfolio" })
→ outputs: DATABASE_URL=postgres://postgres:…@….internal:5432/app
briq_run({
recipe: "python",
stack: "portfolio",
params: {
files: { "app.py": "…reads os.environ['DATABASE_URL']…", "requirements.txt": "flask\npsycopg[binary]" },
env: { DATABASE_URL: { secret: "DATABASE_URL", value: "postgres://postgres:…@….internal:5432/app" } }
},
expose: "private"
})
```
Briqs in one stack reach each other on the private network; only the app gets a URL. The
connection string holds a password, so it goes in as a secret: stored encrypted, shown as
`{ secret: "DATABASE_URL" }` in status and the dashboard, and kept out of the audit log.
## Changing the code
The files you pass are the briq's boot files: written again whenever the process starts over (a
restart, a cold start), so they match what you ran. A resume from a memory snapshot carries on as
it was. To ship a new version, run a new briq with the new files and `briq_destroy` the old one.
`briq_files_put` edits a file in place, until the process starts over. Anything else written on
the briq's disk, installed packages included, survives restarts.
## When it does not start
If the app exits before it answers (a typo, a missing package, the wrong port), the run fails:
the briq is in `error`, and its `error` says how the process exited. `briq_logs` shows the
traceback. `briq_destroy` it, fix the files, and run again (the name is free once it is
destroyed).
If it exits later, the briq stops with `stoppedReason: "exited"` and the code in `lastExit`.
`briq_start` runs the same files again; to change them, run a new briq.
## Good to know
* **Listen on `::`**, not `localhost`: the private network is IPv6, and `::` takes IPv4 too.
* **256 KB of files in all.** A bigger app runs from its repo.
* **Data you cannot lose** goes in a database briq, or on a `volume`.
* **You already have an image?** Run it with `image` instead of a recipe; `files` (absolute
paths, like `/app/server.py`), `ports` and `expose` (with a single port) work the same.
---
# Run a GitHub repo
URL: https://briq.cloud/docs/guides/run-a-github-repo
> An app from a repo, running with a URL. The briq downloads the code itself, and nothing is built on your side.
Recipes:
- [Python app](https://briq.cloud/cookbook/python.md): Your Python code running as a service, from files or a GitHub repo: it installs requirements.txt and starts it. No image to build.
- [Node.js app](https://briq.cloud/cookbook/node.md): Your Node.js code running as a service, from files or a GitHub repo: it installs package.json and starts it. No image to build.
- [Bun app](https://briq.cloud/cookbook/bun.md): Your TypeScript or JavaScript running on Bun, from files or a GitHub repo: it installs package.json and starts it. No build step.
- [Go app](https://briq.cloud/cookbook/go.md): Your Go code running as a service, from files or a GitHub repo: it builds the module and starts the binary. No image to build.
- [Ruby app](https://briq.cloud/cookbook/ruby.md): Your Ruby code running as a service, from files or a GitHub repo: it bundles the Gemfile and starts it. No image to build.
- [Rust app](https://briq.cloud/cookbook/rust.md): Your Rust crate running as a service, from files or a GitHub repo: it builds a release and runs it. No image to build.
- [PHP app](https://briq.cloud/cookbook/php.md): Your PHP code served by PHP's built-in server, from files or a GitHub repo. No image to build.
- [Static site](https://briq.cloud/cookbook/static.md): HTML, CSS, JavaScript and images served by nginx, from files or a folder of a GitHub repo. No build, no image.
- [Nginx gateway](https://briq.cloud/cookbook/nginx.md): A gateway (reverse proxy): one URL for several briqs of a stack, routed by path (/api/ to the back end, / to the front end). One origin for the browser, nothing to change in the apps.
Ask your agent to "run github.com/acme/shop". It passes the repo's address, and the briq downloads
the code itself.
## One call
```text
briq_run({
recipe: "node",
params: {
repo: { url: "github.com/acme/shop" },
build: "npm run build",
start: "npm start",
port: 3000
},
expose: "private"
})
→ bq_7f1… app (node:22-slim) running · url: https://app-x2kd.briq.run/?briq_token=… · …
```
## What happens
1. The briq downloads the branch's latest commit, unless its volume already has it.
2. It installs dependencies when a lockfile changed.
3. It runs `build` when the commit changed.
4. It runs `start` with `PORT` set, and waits until the port answers.
A first build can take minutes. `briq_status` shows `creating` meanwhile, and `briq_logs` shows each
step.
## What `repo` takes
| Field | What it is |
| ------- | --------------------------------------------------------------------------------------------------------------------------- |
| `url` | `github.com/acme/shop`, `https://github.com/acme/shop.git` or `acme/shop`. On another host: an [archive URL](#another-host) |
| `ref` | A branch, a tag or a commit sha. Default: the default branch. A full sha pins the code |
| `dir` | The app's folder in the repo, like `backend`. Install, build and start run there |
| `token` | For a [private repo](#a-private-repo) |
The recipe also takes `install`, `build`, `start`, `port` (8080), `env`, `size` and `diskGb` (2 GB).
## Each language
| Recipe | Installs | Starts with |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------ | --------------------- |
| [node](https://briq.cloud/cookbook/node) | `npm ci`, `pnpm install` or `yarn install`, by lockfile; pnpm at the version in `packageManager` or `engines.pnpm` | `npm start` |
| [bun](https://briq.cloud/cookbook/bun) | `bun install` | `bun run start` |
| [python](https://briq.cloud/cookbook/python) | `requirements.txt`, or `pyproject.toml` (editable) | `python app.py` |
| [ruby](https://briq.cloud/cookbook/ruby) | `bundle install` | `ruby app.rb` |
| [php](https://briq.cloud/cookbook/php) | nothing | PHP's built-in server |
| [go](https://briq.cloud/cookbook/go) | builds at each start, from its cache | the binary |
| [rust](https://briq.cloud/cookbook/rust) | builds at each start, from its cache | `cargo run --release` |
| [static](https://briq.cloud/cookbook/static) | nothing: serves `dir` as it is | nginx |
Take `start` and `port` from the README. A Next.js app: `build: "npm run build"`, `start: "npm start"`,
`port: 3000`.
## Another host
On GitLab, Bitbucket or Codeberg, pass the `https` URL of a `.tar.gz` archive of the code:
```text
repo: { url: "https://gitlab.com/acme/shop/-/archive/main/shop-main.tar.gz" }
```
* The briq downloads it at each start, and unpacks it only when it changed.
* `ref` does not apply: the version is in the URL.
* A private archive takes `token`, sent as `Authorization: Bearer`.
## A new commit
* A briq starting from scratch looks the branch up again.
* `nano` and `small` wake from a memory snapshot: the app keeps its commit.
* `medium` and `large` start from scratch on each wake. A new commit is built before the app answers.
* To run a new commit now: `briq_fork` the briq, then `briq_destroy` the old one.
* To pin a version: pass a full commit sha as `ref`.
## Several services
One briq per service, each with its own `dir`, and an [Nginx gateway](https://briq.cloud/cookbook/nginx) in front.
The browser sees one URL: no CORS, no back end address built into the front end. Run each call once
the one before is running.
Here is [fastapi/full-stack-fastapi-template](https://github.com/fastapi/full-stack-fastapi-template):
```text
briq_run({ recipe: "postgres", stack: "shop" })
→ outputs: DATABASE_URL=postgres://postgres:…@….internal:5432/app
briq_run({
recipe: "python", name: "backend", stack: "shop",
params: {
version: "3.14",
repo: { url: "github.com/fastapi/full-stack-fastapi-template", dir: "backend" },
build: "mkdir -p app/frontend && bash scripts/prestart.sh",
start: "fastapi run app/main.py --host :: --port $PORT",
env: {
DATABASE_URL: { secret: "DATABASE_URL", value: "postgres://postgres:…@….internal:5432/app" },
SECRET_KEY: { secret: "SECRET_KEY" },
FIRST_SUPERUSER: "admin@example.com",
FIRST_SUPERUSER_PASSWORD: { secret: "FIRST_SUPERUSER_PASSWORD", value: "…" }
}
}
})
briq_run({
recipe: "bun", name: "frontend", stack: "shop",
params: {
repo: { url: "github.com/fastapi/full-stack-fastapi-template", dir: "frontend" },
build: "VITE_API_URL= bun run build",
start: "bunx sirv-cli ../backend/app/frontend --single --host :: --port $PORT"
}
})
briq_run({
recipe: "nginx", stack: "shop",
params: { routes: { "/api/": "backend:8080", "/docs": "backend:8080", "/": "frontend:8080" } },
expose: "private"
})
→ url: https://gateway-k3m9.briq.run/?briq_token=…
```
* **Name each code briq** (`name`): briq names are unique in a stack.
* **Empty the front end's API address** at build time (`VITE_API_URL=`): it then calls `/api/…`.
* **Serve the folder the build writes to**: here `../backend/app/frontend`, set in `vite.config.ts`.
* **Listen on `::`**: the gateway reaches the briqs over the private network, which is IPv6.
* **Migrations go in `build`**: they run once per new commit.
## A private repo
Ask the person for a fine-grained token, at github.com/settings/personal-access-tokens/new:
1. **Repository access**: *Only select repositories*, this repo only.
2. **Permissions**: *Contents*, read-only. Nothing else.
3. Set an expiration. An organization may have to approve the token.
```text
repo: {
url: "github.com/acme/internal-api",
token: { secret: "GITHUB_TOKEN", value: "github_pat_…" }
}
```
* The token is stored encrypted, and shown as `{ secret: "GITHUB_TOKEN" }`.
* Only the download gets it: not the install, the build or the app. `briq_exec` can still read it,
like any secret.
* Never pass the person's own token (`gh auth token`): it reaches every repo they can reach.
* Delete the token once the briq is gone.
## When it does not start
`briq_logs` says which step failed:
| The logs say | Fix |
| -------------------------------- | --------------------------------------------------------------------------------- |
| `could not read … from GitHub` | Check the URL. A private repo needs `token` |
| `… has no branch or tag named …` | Check `ref` |
| `the repo has no folder …` | Check `dir` |
| An install or build error | Fix the repo and push, or run a new briq with other `install`, `build` or `start` |
## Good to know
* **Builds need CPU.** On `small`, a Next.js, Rust or Go build can take over ten minutes. Use
`medium`, or `large` (Hobby: with a card on file, see [pay as you go](https://briq.cloud/docs/cost#pay-as-you-go)).
* **A monorepo builds from its root**: `build: "cd /work/src && pnpm -w build"`. `pnpm` and `yarn`
work in `build` and `start`.
* **The volume counts toward your plan's disk** until the briq is destroyed, stopped or failed
ones included. Big dependencies need `diskGb: 5` or more.
* **A fork starts warm**: it copies the volume, code and dependencies included.
* **An app on `0.0.0.0`** works through its URL. Siblings need it on `::`.
---
# Run tests against real services
URL: https://briq.cloud/docs/guides/run-tests-against-real-services
> Replace mocks with a real Postgres and Redis for the duration of a test run.
Recipes:
- [PostgreSQL](https://briq.cloud/cookbook/postgres.md): A PostgreSQL database with a persistent volume. Optional pgvector.
- [Redis](https://briq.cloud/cookbook/redis.md): A Redis server (Valkey-compatible) for caches and queues.
Mocks drift, and Testcontainers needs Docker, which cloud sandboxes and CI runners often lack. briq
gives a test run real services for a few cents and tears them down after.
Recipe outputs are private addresses that only briqs of your team can reach, so the tests run in a
briq too, in the same stack as the services.
## From an agent
> Run the integration tests against a real Postgres and Redis instead of the mocks.
The agent starts the `postgres` and `redis` recipes and a runner in the same stack, runs the tests
there with the outputs as env, destroys the stack's briqs, and can tell you what the run cost.
## Run in briq
```text
briq_run({ recipe: "postgres", stack: "ci" })
briq_run({ recipe: "redis", stack: "ci" })
briq_run({ image: "node:22", stack: "ci", cmd: ["sleep", "infinity"],
env: { DATABASE_URL: { secret: "DATABASE_URL", value: "" },
REDIS_URL: "" } })
briq_files_put({ briq: "bq_…", path: "/app.tgz", contentBase64: "…" })
briq_exec({ briq: "bq_…", cmd: ["sh", "-c", "tar xzf /app.tgz -C / && cd /app && npm ci && npm test"], timeoutMs: 600000 })
```
`DATABASE_URL` holds a password, so it goes in as a secret: plain env values show in status and on
the dashboard. `briq_exec` shows the first 32 KB of output: send long output to a file and read it
with `briq_files_get`.
## From CI
The same calls over [REST](https://briq.cloud/docs/api/overview). `sleep: "30m"` puts everything to sleep 30 minutes
after the job last used it, even if the job dies before its cleanup step. A sleeping briq is not
billed, but its disk counts toward the plan's allowance until it is destroyed.
```bash title="ci/integration.sh"
api() { local p=$1; shift; curl -sf "https://api.briq.cloud/v1$p" \
-H "Authorization: Bearer $BRIQ_API_KEY" -H "Content-Type: application/json" "$@"; }
DB=$(api /briqs -d '{ "recipe": "postgres", "stack": "ci", "sleep": "30m" }')
CACHE=$(api /briqs -d '{ "recipe": "redis", "stack": "ci", "sleep": "30m" }')
RUNNER=$(api /briqs -d "$(jq -n --argjson db "$DB" --argjson c "$CACHE" '{ stack: "ci", spec: {
name: "runner", image: "node:22", cmd: ["sleep", "infinity"], sleep: "30m",
env: { DATABASE_URL: { secret: "DATABASE_URL", value: $db.outputs.DATABASE_URL },
REDIS_URL: $c.outputs.REDIS_URL } } }')")
ID=$(jq -r '.briqs[0].id' <<<"$RUNNER")
git archive HEAD | gzip | base64 | jq -Rs '{ path: "/app.tgz", contentBase64: . }' \
| api "/briqs/$ID/files" -d @- >/dev/null
api "/briqs/$ID/exec" -d '{ "timeoutMs": 600000, "cmd": ["sh", "-c",
"mkdir -p /app && tar xzf /app.tgz -C /app && cd /app && npm ci && npm test"] }' \
| tee result.json | jq -r .stdout
STATUS=$(jq .exitCode result.json)
for id in $(jq -r '.briqs[].id' <<<"$DB $CACHE $RUNNER"); do api "/briqs/$id" -X DELETE >/dev/null; done
exit "$STATUS"
```
Uploads are capped at 1 MB a file; for a repo, have the runner `git clone` it instead.
`nano` is enough for Redis and most test databases.
---
# Try a migration on a fork
URL: https://briq.cloud/docs/guides/try-a-migration-on-a-fork
> Let an agent run a risky change on a copy of the database, then keep it or throw it away.
An agent about to run a migration, a backfill or a `DELETE … WHERE` it is unsure of can try it on a
copy first.
## Ask for it
> Before you run the new migration on the dev database, try it on a fork and show me the row counts
> before and after.
1. `briq_fork({ briq: "" })`: a running copy with its own `DATABASE_URL`.
2. `briq_exec` on the fork: the migration, then your queries.
3. The agent reports; the original is untouched.
4. It runs the migration on the original, or not, and destroys the fork.
## Two approaches at once
> Fork the database twice. Try a new column with a backfill on one and a view on the other. Tell me
> which is faster on the report query.
Two forks, `db-fork` and `db-fork-2`, each with its own `DATABASE_URL`. The agent compares them and
destroys the one it does not keep.
## Fork the whole app
When the change spans more than the database, fork the stack:
```text
briq_fork({ stack: "shop", into: "shop-v2" })
```
Every briq gets a copy in `shop-v2` under the same name, so the forked API talks to the forked
database. Expose the forked API to click through it, then destroy the `shop-v2` briqs.
## Good to know
* Memory is not copied: the forked database starts on the copied disk as after a power cut.
* A fork keeps the source's credentials; only the host changes.
* Forks count against the agent's policy: with `maxConcurrentBriqs: 2`, a two-briq stack cannot be
forked while it runs.
---
# Expose a preview URL
URL: https://briq.cloud/docs/guides/expose-a-preview-url
> Give a running service an HTTPS URL, public or private.
Briqs are private. Publishing gives one port of a briq its own HTTPS URL, either as you run it
(`expose` on `briq_run`) or later with `briq_expose`. A URL is public or private:
| Mode | Who can open it | Use |
| --------- | --------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `private` | Only whoever has the URL you were given | Anything only you, or the people you send it to, should see: an app in progress, a preview for a reviewer, an admin UI, webhooks from a known sender |
| `public` | Anyone on the internet | A demo or a site meant for everyone, webhooks from anyone |
A private URL carries a secret, `?briq_token=`. briq checks it before a request reaches your
service and turns away every request without it. On the first visit, the browser keeps it as a
cookie and lands on the clean address, so links inside your app work as usual.
```text
briq_run({ image: "ghcr.io/acme/web:pr-412", name: "web", stack: "preview", ports: [3000],
env: { PORT: "3000" }, expose: "private" })
→ bq_9a2fk3m8q1zt web (ghcr.io/acme/web:pr-412) running · …internal · url: https://web-k7x3.briq.run/?briq_token=… · cost so far … · sleeps at 19:10 UTC unless used
outputs:
URL=https://web-k7x3.briq.run/?briq_token=…
```
The URL is known as soon as the run answers, `wait: false` included, and serves once the briq
runs. Recipes with a web UI publish their front door the same way:
`briq_run({ recipe: "grafana", expose: "private" })`.
`briq_expose({ briq, port, mode })` publishes a briq that is already running, or switches its
mode. Its front door (the recipe's, or a briq's only port) is published at once. Another port
moves the URL there and restarts the machine to deliver it: the processes start over, and files
on its disk are kept. Without `mode`, the URL keeps the mode it has: moving a private URL to
another port never opens it.
## Good to know
* **Listen on `::`**, not `localhost` or `0.0.0.0` alone: the private network is IPv6-only.
* **HTTP only.** Keep databases private and reach them from another briq.
* **Stable address**: `https://-.briq.run`, the suffix four random characters
drawn on the first expose. It lasts as long as the briq, and exposing again keeps it, token
included. A new briq gets a new suffix, even under the same name.
* **An app that needs its own address at boot** (links in emails, an OAuth callback, a `BASE_URL`):
publish it as you run it and write `{{self:host}}` in a plain `env` value, for example
`env: { BASE_URL: "https://{{self:host}}" }`. briq puts the URL's hostname there before the app
starts. A briq published later gets `localhost`.
* **One URL per briq.** Exposing another port moves the URL to that port.
* **A private link that leaked**: `briq_expose({ briq, port, rotate: true })`, or "New token" on
the briq's page in the dashboard. The URL stays; links and cookies with the old token stop
working.
* **Visits keep the stack awake**, and wake it when it sleeps. A URL can stay up for months this
way, billed only while it is used (`sleep: "30m"` sleeps it after half an hour without
visits). A briq stopped by `briq_stop`, its own exit or a limit answers 503 until started or
until the limit clears; a destroyed briq loses its URL.
* **Limits**: a public URL has no token to rotate, and a briq declares at most 32 ports, so
exposing a new one past that is refused.
---
# Connect to a database from outside
URL: https://briq.cloud/docs/guides/connect-to-a-database-from-outside
> A briq's database reachable from psql, a BI tool or an app elsewhere, over TLS, with a normal connection string.
Recipes:
- [PostgreSQL](https://briq.cloud/cookbook/postgres.md): A PostgreSQL database with a persistent volume. Optional pgvector.
- [MySQL](https://briq.cloud/cookbook/mysql.md): A MySQL database with a persistent volume.
- [Redis](https://briq.cloud/cookbook/redis.md): A Redis server (Valkey-compatible) for caches and queues.
- [MongoDB](https://briq.cloud/cookbook/mongo.md): A MongoDB server with authentication and a persistent volume.
- [RabbitMQ](https://briq.cloud/cookbook/rabbitmq.md): AMQP message broker with the management UI enabled.
- [Neo4j](https://briq.cloud/cookbook/neo4j.md): A graph database with a persistent volume, for data an agent should query, not paraphrase.
- [Qdrant](https://briq.cloud/cookbook/qdrant.md): A vector database, for a knowledge file the agent can search by meaning, not grep.
Ask your agent to "give me a connection string for the database". It gives the briq a TCP
endpoint: the port, and the protocol it speaks.
```text
briq_expose({ briq: "bq_7f1…", port: 5432, protocol: "postgres" })
→ postgres TCP endpoint for port 5432:
postgres://postgres:…@db-k3m9x2p7qa.tcp.briq.run:5432/app?sslmode=require
```
In the dashboard: the briq's page, **Endpoints**, **tcp**: pick the port and the protocol, then
**Expose**.
## What happens
1. The TCP endpoint gets a hostname, `-<10 characters>.tcp.briq.run`, kept for the briq's
life.
2. briq's edge serves it on the protocol's usual port, over TLS 1.2 or later, and refuses
plaintext.
3. A connection wakes a sleeping briq, and an open connection keeps its stack awake.
## Each protocol
| `protocol` | Recipes | Edge port | Connection string |
| ---------- | -------------------------------------------- | --------- | ------------------------------------------- |
| `postgres` | [postgres](https://briq.cloud/cookbook/postgres) | 5432 | `postgres://…?sslmode=require` |
| `mysql` | [mysql](https://briq.cloud/cookbook/mysql) | 3306 | `mysql://…?ssl-mode=REQUIRED` |
| `redis` | [redis](https://briq.cloud/cookbook/redis) | 6379 | `rediss://default:…@…:6379` |
| `mongodb` | [mongo](https://briq.cloud/cookbook/mongo) | 27017 | `mongodb://…?authSource=admin&tls=true` |
| `amqp` | [rabbitmq](https://briq.cloud/cookbook/rabbitmq) (5672 inside) | 5671 | `amqps://…:5671` |
| `bolt` | [neo4j](https://briq.cloud/cookbook/neo4j) | 7687 | `neo4j+s://…:7687`, user and password apart |
| `grpc` | [qdrant](https://briq.cloud/cookbook/qdrant) (6334) | 6334 | `https://…:6334`, with the `api-key` header |
A recipe's database ports are listed in `briq_status` as `databasePorts`. Its endpoint answers with
the full connection string, password included. Another briq's (your own image) answers with the
address: add its user and password.
## Send the hostname
The edge finds the database by the name the client sends in TLS (SNI). Connect by name, never by
IP address. Most clients send it; these need an option:
| Client | Option |
| -------------------------- | --------------------------------------------------------------------------------- |
| `redis-cli` | `--tls --sni ` |
| ioredis | `tls: { servername: host }` |
| node-redis | `socket: { tls: true, servername: host }` |
| `mysql` CLI (8.1 or later) | `--ssl-mode=VERIFY_IDENTITY --tls-sni-servername=` |
| psql, libpq | 14 or later; `sslmode=verify-full&sslrootcert=system` also checks the certificate |
## The password is the gate
* There is no URL token: whoever has the connection string can connect. Keep it secret.
* Recipes generate passwords of about 140 bits.
* The edge refuses a Postgres, Redis or MongoDB that lets anyone in. Set a password on your own
image before you expose it. For MySQL, AMQP, Bolt and gRPC, make sure the service asks for one.
* After 10 failed logins in 10 minutes, the edge refuses that address for 10 minutes (Postgres,
MySQL, Redis).
## When it does not connect
Errors from the edge start with `briq:`.
| The client says | Fix |
| ------------------------------------------------- | ---------------------------------------------------------------------------- |
| `TLS is required` | Turn TLS on: `sslmode=require`, `rediss://`, `tls=true`, `ssl-mode=REQUIRED` |
| `no server name (SNI)` | Connect by hostname; add the option above |
| `no Postgres endpoint named …` (or Redis, MySQL…) | Check the hostname, and that the port is the protocol's |
| `lets anyone in` or `has no password` | Set a password on the service, then connect again |
| `the database is stopped` | Start the briq; a sleeping one wakes on its own |
| `too many failed logins` | Wait 10 minutes; check the password |
A MongoDB that lets anyone in is refused by closing the connection. Some clients (ioredis) show
only that the connection closed: try `redis-cli` or `psql` to read the edge's message.
## Good to know
* **Unlimited on every plan**, like HTTPS URLs.
* **Destroying the briq removes its endpoint.** Exposing again gives the same one.
* **Briqs of the same stack** use the internal address (`DATABASE_URL` and the like), not this one.
---
# Report on a dataset
URL: https://briq.cloud/docs/guides/report-on-a-dataset
> Load a public dataset into Postgres, chart it in Metabase, and share a link to the dashboard.
Recipe:
- [Metabase](https://briq.cloud/cookbook/metabase.md): Reports on a Postgres warehouse: load a dataset, build a dashboard, share a link to it.
You want the answer to a question about some data as a dashboard you can send, not a table in
chat. The agent loads the data into a Postgres, charts it in [Metabase](https://briq.cloud/cookbook/metabase)
(open source BI) and gives you a link. Here: where the world's electricity comes from, from Our
World in Data. First, [connect your agent](https://briq.cloud/docs/getting-started).
## Ask
> Start Metabase on briq, load 'Our World in Data' energy dataset into it, generate a report on
> world energy generation, and share it with me.
## What the agent does
**1. Start the stack.** One recipe, two briqs: a Postgres warehouse, and Metabase already set up
with the warehouse connected, read-only. `expose: "private"` gives Metabase a URL only whoever
has it can open.
```text
briq_run({ recipe: "metabase", stack: "reports", expose: "private" })
→ postgres running · metabase running · url: https://metabase--reports--acme.briq.run/?briq_token=…
```
**2. Load the data.** Through `briq_exec` in the `postgres` briq, which downloads the file
itself, so the data never goes through the agent. One row per country and year, and some 130
measures: electricity by source in TWh (`fossil_electricity`, `nuclear_electricity`,
`renewables_electricity`, `solar_electricity`…), their shares in %, energy use. The table's columns
come from the file's header: `country` and `iso_code` are text, `year` an integer, the rest
numbers.
```sh
wget -qO /tmp/energy.csv https://raw.githubusercontent.com/owid/energy-data/master/owid-energy-data.csv
cols=$(head -1 /tmp/energy.csv | sed 's/,/ numeric, /g; s/$/ numeric/; s/^country numeric/country text/;
s/year numeric/year int/; s/iso_code numeric/iso_code text/')
psql -U postgres -d warehouse -c "CREATE TABLE energy ($cols)" -c "\copy energy from /tmp/energy.csv with (format csv, header)"
```
Rows without an `iso_code` are aggregates (World, continents, income groups, the same regions as
each source draws them): `country = 'World'` gives the totals (its `iso_code` is empty, not
`OWID_WRL`), `iso_code IS NOT NULL` keeps the countries.
World figures run to 2025.
**3. Build the dashboard.** Through `briq_exec` in the `metabase` briq, where `mb` calls
Metabase's API. A chart is a SQL query and a display (`table`, `row`, `line`, `scalar`…); the
dashboard places it:
```sh
mb POST /api/card '{"name": "Largest producers, 2025 (TWh)", "display": "row",
"visualization_settings": {"stackable.stack_type": "stacked"}, "dataset_query": {"type": "native", "database": 1,
"native": {"query": "select country, fossil_electricity as fossil, nuclear_electricity as nuclear,
renewables_electricity as renewables from energy where iso_code is not null and year = 2025
order by electricity_generation desc nulls last limit 12"}}}'
mb POST /api/dashboard '{"name": "Where the world'\''s electricity comes from"}'
mb PUT /api/dashboard/1 '{"dashcards": [{"id": -1, "card_id": 1, "row": 0, "col": 0, "size_x": 12, "size_y": 8}]}'
```
One card per question: the world by source since 1985, solar and wind against hydro, the
low-carbon share of the largest producers, renewables' share country by country.
**4. Share it.** A public link shows that one dashboard, read-only, without an account:
```sh
mb POST /api/dashboard/1/public_link
→ {"uuid":"26caf580-…"}
```
The link to send is the briq's private URL with the dashboard's path:
`https://metabase--reports--acme.briq.run/public/dashboard/26caf580-…?briq_token=…`. briq turns
away every request without the token before it reaches Metabase, so only people with the link see
the report.
## Tips
* **First boot takes about three minutes** while Metabase migrates its database.
* **Polish it by hand** at `URL`, signed in with `METABASE_ADMIN_EMAIL` and
`METABASE_ADMIN_PASSWORD`.
* **Fresh data, same dashboard**: Our World in Data updates the file as Ember and the Energy
Institute publish; load it again and every chart, a query run on each view, follows.
* **Withdraw the link** with `briq_expose({ briq, port: 3000, rotate: true })`: the URL stays, the
old token stops working. Destroy both briqs when the report has served its purpose.
---
# Budgets
URL: https://briq.cloud/docs/guides/budgets
> Hand an agent a budget instead of your account.
Every agent has a [policy](https://briq.cloud/docs/concepts/keys-and-policy#the-policy), checked before each create
and start and enforced while its briqs run. A connected client gets one when you approve it, an
API key when you create it. Edit either on the **Agents** page. Nothing can exceed what your plan
allows you, and only a person can create, change or revoke a key: an API key gets `403 forbidden`
on those routes.
## Suggested budgets
| Use | `dailySpendCapCents` | `maxConcurrentBriqs` | `allowedSizes` | `maxSleep` |
| ------------------------- | -------------------- | -------------------- | ------------------- | ---------- |
| Agent on a laptop | 200 | 2 | nano, small | `"1d"` |
| CI job | 100 | 3 | nano, small | `"1h"` |
| Shared team key for demos | 1000 | 5 | nano, small, medium | `"7d"` |
A cap is not there to save money; it makes an infinite loop finite.
## Create a key with a budget
On the **Agents** page, or from a signed-in dashboard session:
```bash
curl -X POST https://api.briq.cloud/v1/keys \
-H "Cookie: …session…" -H "Content-Type: application/json" \
-d '{
"name": "claude-code laptop",
"policy": { "dailySpendCapCents": 200, "maxConcurrentBriqs": 2, "maxSleep": "1d" }
}'
```
Unset fields take the defaults. An API key cannot create keys or edit a policy (`403 forbidden`),
so an agent never raises its own budget.
## What the agent sees
`briq_quota` returns what is left, so the model can plan. At a limit, `briq_run` fails with
`quota_exceeded` and a message the model relays to you. Crossing the daily cap mid-run stops the
agent's briqs; from the next UTC day they are asleep, and the next use wakes them.
## Rotate and revoke
Give each agent or environment its own key, so you can revoke one without touching the others. Set
`expiresAt` on keys for short-lived environments. The audit log attributes every call to its key.
---
# MCP tools
URL: https://briq.cloud/docs/mcp/tools
> Every tool the briq MCP server exposes, with input, output and an example call.
The server is at `https://api.briq.cloud/mcp`. Tools mirror the [REST API](https://briq.cloud/docs/api/overview).
Every result about a briq ends with its cost line:
```text
bq_7kq2m9x1p4ab db (postgres:16) running · …internal · cost so far … · sleeps at 18:42 UTC unless used
```
## briq\_run
Create and start a briq from a recipe or an image. Returns once it is ready: its healthcheck
passes, or without one its process has started.
| Field | Notes |
| ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `recipe` or `image` | `recipe` names a [cookbook](https://briq.cloud/cookbook) entry; `image` is any public OCI image |
| `params` | Recipe parameters. A language recipe takes your code here: `params.files`, `params.env`. A recipe that keeps data takes `diskGb`, its volume's size |
| `expose` | `"private"` for a URL only whoever has it can open, `"public"` for anyone. Publishes the recipe's front door, or the image's single port, and returns `URL` |
| `name` | Unique in the stack. Default: the recipe's briq name, or the image name |
| `stack` | Default `default`; created if missing |
| `env` | Image only. A string, `{ "secret": "NAME" }` for a generated secret, or `{ "secret": "NAME", "value": "…" }` for a credential you already have. Plain values show in status: credentials always go as secrets |
| `cmd`, `entrypoint`, `ports`, `size` | Image only. Size `nano`, `small` (default), `medium`, `large` |
| `files` | Image only. Absolute path → text or `{ "base64": "…" }`, written before the process starts. 64 files, 256 KB in all |
| `volume` | Image only. `{ mount, gb? }`: a durable disk for data you cannot lose, 2 GB unless `gb` says more |
| `healthcheck` | Image only. `{ cmd, timeoutMs? }`: `briq_run` waits until it passes |
| `sleep` | When it goes to sleep: after this long without use, a string such as `"30m"`, `"3h"`, `"7d"`, or `"never"` (always on, Pro plan and above). Never a number. Default `"1h"` on briq.cloud; with a recipe, every briq it makes gets the same. See [Sleep](https://briq.cloud/docs/concepts/lifecycle-and-sleep#sleep) |
| `wait` | Default `true`: return once ready, for up to two minutes. A briq still `creating` then is on its way: check `briq_status` |
With `recipe`, the image-only fields are refused: pass them in `params`, as the recipe's
[cookbook](https://briq.cloud/cookbook) page lists them.
**Output**: the briqs (id, state, host, endpoints), the `outputs` (a recipe's connection strings,
secrets briq generated, `URL`), the cost line. A secret you passed in is not printed back.
```text
briq_run({ recipe: "postgres", params: { version: "16" } })
→ bq_7kq2m9x1p4ab db (postgres:16) running · …internal · cost so far … · sleeps at 18:42 UTC unless used
outputs:
DATABASE_URL=postgres://postgres:…@…internal:5432/app
```
## briq\_exec
Run a command in a briq. **Input**: `{ briq, cmd: string[], timeoutMs?, stdin? }`. `cmd` is an
argv run without a shell: `["psql", "-c", "select 1"]`, not `["psql -c 'select 1'"]` (that looks
for a program named after the whole line, and fails with exit 127); for pipes, globs, `&&` or
`$VARS`, pass `["sh", "-c", "…"]`. `timeoutMs`
60000 by default, at most 600000; keep the command under about 16 KB and send bigger input as
`stdin`. **Output**: exit code, stdout and stderr (stdout truncated at 32 KB). A sleeping briq is
woken first, so the call is slower. On a stopped briq, an error that says why: `invalid_state`
(409) after a stop or an exit (with the code), `quota_exceeded` or `payment_required` (402) while
a limit holds.
```text
briq_exec({ briq: "bq_7kq2m9x1p4ab", cmd: ["psql", "-U", "postgres", "-c", "select count(*) from orders"] })
→ exit 0
count
-----
1284
cost so far … · sleeps at 18:42 UTC unless used
```
## briq\_logs
**Input**: `{ briq, since?, limit? }` (`since` is the `next` cursor of a previous call, `limit` up
to 1000). **Output**: log lines and `next`.
## briq\_files\_put / briq\_files\_get
Write or read one file, base64, up to 1 MB each way. **Input**: `{ briq, path, contentBase64 }` /
`{ briq, path }`. A larger file is refused with a `validation` error that says so, in both
directions: move it from inside the briq instead (`git clone`, `curl`), or read part of it with
`briq_exec`. A 1 MB write takes up to half a minute. Writing one of the briq's
[boot files](https://briq.cloud/docs/concepts/briq#files) answers with a `warning`: the spec writes it again at the
next start.
A write answers with the file's `sha256`, and `verified: true` when the briq computed the same
digest from its disk (its image has `sha256sum`): compare it with your copy's. Line breaks in the
base64 are ignored; base64 whose length shows it was cut short is refused with a `validation`
error, rather than written and found broken later.
```text
briq_files_put({ briq: "bq_7kq2m9x1p4ab", path: "/seed.sql", contentBase64: "aW5zZXJ0…" })
briq_exec({ briq: "bq_7kq2m9x1p4ab", cmd: ["psql", "-U", "postgres", "-f", "/seed.sql"] })
```
## briq\_expose
Give the briq its HTTPS URL, on one port, or a TCP endpoint. **Input**: `{ briq, port,
protocol?, mode?, rotate? }`. `mode` is
`private`, a URL only whoever has it can open (it carries a secret checked before any request
reaches the briq), or `public`, open to anyone. Without `mode`, a URL the briq already has keeps
its mode, and a first URL is `public`.
* A briq has one URL. Its front door (the recipe's, or a briq's only port) publishes at once.
Another port moves the URL there and restarts the machine: the processes start over, files on
disk are kept, and the result carries a `note` saying so.
* `rotate: true` gives a private URL a new token: the URL stays, links and cookies with the old
token stop working. A public URL has none to rotate.
* A briq declares at most 32 ports; exposing a new one past that is refused.
* `protocol` is `http` by default. A database protocol (`postgres`, `mysql`, `redis`, `mongodb`,
`amqp`, `bolt`, `grpc`) makes a TCP endpoint: reachable from outside over TLS, for any
briq. A recipe's database port refuses `http` and names its protocol. `mode` does not apply: the
password is the gate. See
[Connect to a database from outside](https://briq.cloud/docs/guides/connect-to-a-database-from-outside).
See [Expose a preview URL](https://briq.cloud/docs/guides/expose-a-preview-url).
```text
briq_expose({ briq: "bq_9a2fk3m8q1zt", port: 3000, mode: "private" })
→ exposed port 3000 (private): https://api-k7x3.briq.run/?briq_token=…
```
## briq\_fork
Copy a briq, or a whole stack, before a change you might want to undo. See
[Forks](https://briq.cloud/docs/concepts/fork).
| Field | Notes |
| --------------------- | --------------------------------------------------------------------- |
| `briq` or `stack` | `briq` forks one briq; `stack` alone forks the whole stack |
| `name` | One briq: the fork's name. Default `-fork` |
| `stack` (with `briq`) | One briq: the stack to put the fork in. Default: the same |
| `into` | Whole stack: the new stack. Default `-fork` |
| `sleep` | Default: the source's. A window longer than the key allows is refused |
| `wait` | Default `true` |
**Output**: the forks, what each copied (`disk` or `config`), outputs pointing at the forks, the
cost line.
## briq\_stop / briq\_start / briq\_destroy
**Input**: `{ briq }`. Stop keeps the disk, volume and every other file; destroy removes it. Each
returns once the move lands (up to 30 s); a `stopping`, `starting` or `destroying` state means it
is still on its way, and calling again is safe. A briq stopped by `briq_stop` or its own exit stays
stopped until `briq_start`. One stopped by a limit sleeps once the limit clears. A sleeping one
needs neither: the next call or visit wakes it.
## briq\_set\_sleep
Change when a briq goes to sleep. **Input**: `{ briq, sleep, stack? }`: `sleep` as in `briq_run`,
`stack: true` for every briq of its stack. A running briq sleeps the new window from now; a
sleeping one keeps sleeping until its next use. Not needed for ordinary work: every call and every
visit already pushes the sleep back.
```text
briq_set_sleep({ briq: "bq_7kq2m9x1p4ab", sleep: "3h" })
→ bq_7kq2m9x1p4ab db (postgres:16) running · …internal · cost so far … · sleeps at 21:12 UTC unless used
```
## briq\_list / briq\_status
**Input**: `{ stack?, all? }` / `{ briq }`. **Output**: state (`running`, `sleeping`, `stopped`…),
image, host, cost and when it sleeps per briq; for one, also why it stopped (`stoppedReason`), its last process exit (`lastExit`),
endpoints, env (secrets masked) and boot files (path and size).
## briq\_quota
**Input**: `{}`. **Output**: spend today against the daily cap, credits left, live briqs and how
many more are allowed, allowed sizes, the longest sleep. The spend and the live briqs that count toward the
limit are this credential's own: an agent that signed in again has a new one, so briqs it started
before show in the team's count (`teamLiveBriqs`) and in `briq_list`, not in its own.
## briq\_catalog
**Input**: `{ name? }`. **Output**: every recipe with a one-line description; with `name`, every
parameter it takes (type, default, what it does), its outputs and briqs.
## briq\_docs
**Input**: `{ page? }`. Without `page`, the index of every docs, cookbook and legal page
([`/llms.txt`](https://briq.cloud/llms.txt)); with it, that page as Markdown: `concepts/fork`, `cookbook/postgres`,
`legal/dpa`.
## briq\_feedback
**Input**: `{ topic: "bug" | "idea" | "question", message }`. Emails the people who build briq.
For when briq does not do what these docs say, an error has no explanation (a 5xx), the docs miss
something, or there is an idea. The answer goes by email to the person who connected the agent
(or the team's owner), who also gets a copy; the team's audit log records it as `support.send`.
**Output**: the request id to quote, and who will get the answer. Five per ten minutes.
## Resources and prompts
* `briq://recipes/`: a recipe's parameters, outputs and briqs.
* `briq://docs/`: every page `briq_docs` can read.
* Prompt `briq_getting_started`: how to use the tools well (prefer recipes, reuse a stack, read
the cost line, destroy what you created).
## Transport and auth
Streamable HTTP, stateless. Authentication follows the
[MCP authorization spec](https://modelcontextprotocol.io/specification/2026-07-28/basic/authorization):
a request without credentials gets `401` with `WWW-Authenticate` pointing at
`https://api.briq.cloud/.well-known/oauth-protected-resource/mcp`. The authorization server
(`https://app.briq.cloud/api/auth`) supports Client ID Metadata Documents, dynamic client
registration, PKCE (`S256`) and the `briq` and `offline_access` scopes. Access tokens last 30
days; refresh tokens 30 days from their last use, and each one works once. A client that signs in
with a device code (RFC 8628) gets a refresh token too, whatever scopes it asked for; a code
request that names no scope gets the ones the client registered. The code waits 15 minutes for
approval. A sign-in request refused for coming too often (`429`) says how
long to wait: `Retry-After`, and `retry_after_seconds` in the body. An API key
(`Authorization: Bearer bq_live_…`) works too.
---
# REST API overview
URL: https://briq.cloud/docs/api/overview
> Base URL, authentication, errors and conventions.
The MCP server and the dashboard both use this API. Call it from scripts, CI or anything that
speaks HTTP.
```text
https://api.briq.cloud/v1
```
Breaking changes get a new version in the path; new fields do not.
## Authentication
Send an API key, created on the dashboard's **Agents** page, as a Bearer token:
```bash
curl https://api.briq.cloud/v1/briqs -H "Authorization: Bearer $BRIQ_API_KEY"
```
Access tokens of signed-in MCP clients work too, under the policy approved for that client.
Account and team routes use the dashboard session.
## Conventions
* JSON in and out, camelCase field names (`costCentsSoFar`, `sleepsAt`).
* Money is in euro cents, with decimals for sub-cent amounts.
* Timestamps are ISO 8601, UTC.
* Every response about a briq includes `costCentsSoFar` and `sleepsAt`.
* `sleep` is a string with a unit: `"30m"`, `"3h"`, `"7d"`, or `"never"`. A number there is
refused with the string to send instead.
## Errors
```json
{ "error": { "code": "policy_violation", "message": "size medium not allowed by key policy" } }
```
Every response carries an `x-request-id` header, and an error repeats it as `requestId`. Send
your own `x-request-id` and it is kept. Quote it when you ask us about a call.
| Code | HTTP | When |
| ------------------ | ---- | ----------------------------------------------------- |
| `validation` | 400 | Invalid body or query; `details` lists the issues |
| `unauthorized` | 401 | Missing, expired or revoked credentials |
| `forbidden` | 403 | Not allowed for this credential or plan |
| `policy_violation` | 402 | The agent's policy forbids it (size, registry, sleep) |
| `quota_exceeded` | 402 | Concurrency limit or daily cap reached |
| `quota_exceeded` | 429 | Rate limit; see `retry-after` |
| `payment_required` | 402 | The team is out of credits |
| `not_found` | 404 | Unknown briq, stack or recipe |
| `invalid_state` | 409 | Not possible in the briq's current state |
| `provider_error` | 502 | Infrastructure failure |
Rate limits: 300 requests, 30 creations and 120 execs per minute per credential.
## Audit
Every authenticated call writes an audit row: credential, action, target, duration, and the
client (`via`, `agentName`, `agentVersion`, `userAgent`). Files, and an exec's stdin, are recorded
by size, never their content; env vars by name, never their value; and passwords in a command
(`--password=…`, `PGPASSWORD=…`, a URL's password) are masked. Read it with `GET /v1/audit`
(`?agent=claude-code`, `?key=`) or on the dashboard.
## OpenAPI
[`/v1/openapi.json`](https://api.briq.cloud/v1/openapi.json) describes every endpoint; point any
OpenAPI generator at it for a typed client.
---
# REST reference
URL: https://briq.cloud/docs/api/reference
> Every endpoint an agent uses under /v1.
The full schemas are in [`/v1/openapi.json`](https://api.briq.cloud/v1/openapi.json). This page is
the map.
## Briqs
| Method | Path | Notes |
| -------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `POST` | `/v1/briqs` | `{ recipe, params?, name?, sleep? }` or `{ spec }` ([spec](https://briq.cloud/docs/concepts/briq#a-briq-spec)), plus `stack` and `expose` (`"public"` or `"private"`: the URL comes back as `outputs.URL`). Waits until ready, up to `waitTimeoutMs` (120000), unless `wait: false` |
| `GET` | `/v1/briqs?stack=&all=` | List with state and cost; `all=true` includes destroyed briqs |
| `GET` | `/v1/briqs/:id` | One briq: cost, `sleep` and `sleepsAt`, endpoints, env (secrets masked), `stoppedReason`, `lastExit`, `files` (path and bytes) |
| `POST` | `/v1/briqs/:id/exec` | `{ cmd, timeoutMs?, stdin? }` → `{ exitCode, stdout, stderr }`. `cmd` is an argv, run without a shell: `["sh", "-c", "…"]` for pipes or `$VARS` |
| `GET` | `/v1/briqs/:id/logs?since=&limit=` | Log lines and a `next` cursor |
| `POST` | `/v1/briqs/:id/files` | `{ path, contentBase64 }`, up to 1 MB; larger is a 400 `validation`, and so is base64 cut short (line breaks are fine) → `{ path, bytes, sha256, verified }`: `verified` when the briq computed the same SHA-256 from its disk. A `warning` when the path is a boot file |
| `PUT` | `/v1/briqs/:id/files?path=` | The same, with the raw bytes as the body: `curl -X PUT --data-binary @server.py`; the same answer |
| `GET` | `/v1/briqs/:id/files?path=` | `{ path, contentBase64 }`, up to 1 MB; larger is a 400 `validation` |
| `POST` | `/v1/briqs/:id/expose` | `{ port, mode?, rotate? }` → `{ url, mode, port, warning? }`. One URL per briq: another port moves it and restarts the machine. See [Expose](https://briq.cloud/docs/guides/expose-a-preview-url) |
| `POST` | `/v1/briqs/:id/fork` | `{ name?, stack?, sleep? }`. See [Forks](https://briq.cloud/docs/concepts/fork) |
| `POST` | `/v1/briqs/:id/stop` | Keeps the disk |
| `POST` | `/v1/briqs/:id/start` | Starts a briq stopped by `/stop` or by its own exit. A sleeping briq wakes on its next use without it, and so does one stopped by a limit once the limit has cleared |
| `POST` | `/v1/briqs/:id/sleep` | `{ sleep, stack? }`: `"30m"`, `"3h"`, `"7d"` or `"never"`, a string. `stack: true` for every briq of its stack → `{ briqs }`. See [Sleep](https://briq.cloud/docs/concepts/lifecycle-and-sleep#sleep) |
| `DELETE` | `/v1/briqs/:id` | Destroy |
## Stacks
| Method | Path | Notes |
| ------ | --------------------- | ------------------------------------------------------------ |
| `GET` | `/v1/stacks` | |
| `POST` | `/v1/stacks` | `{ name }`. `POST /v1/briqs` also creates the stack it names |
| `GET` | `/v1/stacks/:id` | The stack and its briqs |
| `POST` | `/v1/stacks/:id/fork` | `{ into?, sleep? }` |
## Recipes and pricing
| Method | Path | Notes |
| ------ | ------------------- | --------------------------------------------------------------------------- |
| `GET` | `/v1/recipes` | Every recipe: name, title, description, tags |
| `GET` | `/v1/recipes/:name` | One recipe: every parameter (type, default, description), outputs and briqs |
| `GET` | `/v1/pricing` | Sizes and prices |
## Agents, quota and audit
| Method | Path | Notes |
| ----------------- | -------------------------------- | ------------------------------------------------------- |
| `GET` | `/v1/quota` | What this credential may still spend and run |
| `GET` | `/v1/audit?limit=&key=&agent=` | The team's audit events |
| `GET` | `/v1/usage?days=` | The team's usage per day (default 14 days) |
| `GET` | `/v1/agents` | Keys and connected clients |
| `GET`, `POST` | `/v1/keys` | List or create keys. Creating needs a dashboard session |
| `PATCH`, `DELETE` | `/v1/keys/:id`, `/v1/agents/:id` | Edit a policy or revoke. Session only |
## Support
| Method | Path | Notes |
| ------ | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `POST` | `/v1/support` | `{ topic: "question" \| "bug" \| "idea", message }` emails the briq team; the answer goes to the account's address (with a key or an agent's token: to the person who connected it, or the team's owner). Five per ten minutes |
## Example
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" -H "Content-Type: application/json" \
-d '{ "recipe": "postgres", "params": { "version": "16" } }'
```
```json
{
"briqs": [
{
"id": "bq_7kq2m9x1p4ab",
"name": "db",
"image": "postgres:16",
"size": "small",
"state": "running",
"internalHost": "…internal",
"endpoints": [],
"sleep": "1h",
"sleepsAt": "2026-09-18T17:41:12Z",
"costCentsSoFar": 0.058,
"…": "…"
}
],
"outputs": { "DATABASE_URL": "postgres://postgres:…@…internal:5432/app" },
"recipe": "postgres",
"costLine": "cost so far … · sleeps at 17:41 UTC unless used"
}
```
A recipe can start several briqs, so `briqs` is a list and `outputs` belongs to the run. Destroy
each id with `DELETE /v1/briqs/:id`.
---
# Cost
URL: https://briq.cloud/docs/cost
> Per-second pricing, four sizes, one currency, and where the numbers show up.
briq bills **per second** from the moment a briq runs until its machine is down: `running`, and
`stopping` until the stop lands (a memory snapshot can take a few seconds). Pulling the image and
waiting for the healthcheck are not billed. A sleeping or stopped briq is not billed for compute, and
its volume is kept until you destroy it. Disk and outbound traffic are not billed today.
| Size | vCPU | RAM | Per hour |
| --- | --- | --- | --- |
| `nano` | shared 1 | 512 MB | €0.01 |
| `small` | shared 1 | 2 GB | €0.045 |
| `medium` | shared 2 | 4 GB | €0.09 |
| `large` | performance 2 | 8 GB | €0.30 |
Hobby runs `large` once the team has a card on file ([pay as you go](#pay-as-you-go)); Pro and
Team run every size ([plans](#plans)).
## Currency and precision
briq bills in **euro**: the balance, every `*Cents` field of the API and every cost line are euro
cents. The pricing tables and the dashboard (per team, in Settings) can display US dollars at the
day's rate; that changes the display only.
Nothing is rounded to a cent: a `small` Postgres that lives 41 seconds is billed 41 seconds, a
fraction of a cent, and that fraction is what the API (`costCentsSoFar`) and the cost line show.
## You pay for the work, not the wait
A briq goes to sleep after its `sleep` window unused (an hour by default), so an agent that runs a
two-minute migration and moves on pays for the work and the hour after it, not for the days the
database stays around. A sleeping briq is not billed, and the next call or visit wakes it with its
data. Always on (`sleep: "never"`, Pro plan and above) is for work that must run without anyone
using it. See [Sleep](https://briq.cloud/docs/concepts/lifecycle-and-sleep#sleep).
## Credits
Every new account gets **€10** of credits on its personal team. Credits are prepaid; usage draws
them down as it runs.
* **Before anything starts** (create, start, fork, a call or visit waking a sleeping stack), the team needs
credits for the first hour of it. Otherwise the call fails with `payment_required` (402) and
says where to top up.
* **At zero**, the team's running briqs stop. Nothing is deleted, and visits do not wake them.
After a top-up they are asleep, and the next call or visit wakes them. The balance can dip
slightly below zero for the few seconds that takes.
* **Disk** is kept while a briq is stopped, up to the [plan](#plans)'s allowance for the
whole team, running and stopped briqs together. Past it, a run with a volume is refused until
something is destroyed. Volumes start small: 2 GB unless the spec sets `gb`, and 1 to 5 GB for
a recipe, which takes `diskGb` for more.
Owners and admins buy credits on the dashboard's Billing page, through Stripe. Prices exclude VAT,
which is added at checkout where it applies (EU businesses with a VAT number are reverse-charged);
each purchase comes with an invoice. The credits are on the team as soon as the payment
clears.
## Pay as you go
With a card on file, the team does not stop at zero: usage past the credits is owed, and charged to
the card each month. Credits are always used first. Pro and Team pay as they go with their
subscription's card, and the usage is a line on the plan's monthly invoice: one invoice, one
charge. On Hobby, add a card on the Billing page (which also lets the team run `large`); its usage
is invoiced on the 1st of each month.
If a charge is refused, the team is back on credits until it is paid: update the card under
"Manage invoices and payment".
## Plans
Every new team starts on Hobby, which is free. Pro and Team are monthly subscriptions. The plan
does not change the prices: it sets how many agents and people a team has, the sizes it runs and
the disk it holds.
| | Hobby | Pro | Team |
| --- | --- | --- | --- |
| Price | Free | €20 / month | €100 / month |
| Included | No monthly fee | €20 of usage included every month | €100 of usage included every month |
| Agents per team | 3 | 25 | 100 |
| Members per team | Just you | 5 | 20 |
| Briq sizes | nano, small, medium briqs | Every briq size | Every briq size |
| Disk held | 10 GB | 250 GB | 1 TB |
| Always-on briqs | no | yes | yes |
| Pay as you go | With a card | yes | yes |
* **Usage included**: a paid plan's price comes back as credits for the month it pays for (the
line under each plan's price). Your briqs spend them before any other credits, so a team that runs less than
that pays nothing more. What is left at the end of the month does not carry over; credits you
bought or were given are not affected. The Billing page shows how much of it is used.
* **Upgrading** takes effect at once.
* **Downgrading or cancelling** takes effect at the end of the month already paid for; nothing is
refunded, and the team keeps its plan until then.
* **Invoices, card and billing details** are under "Manage invoices and payment" on the Billing page.
A call the plan does not allow fails with `plan_limit` (403) and says which plan allows it. Moving a
team down keeps the agents, members, briqs and disk it has; only new ones are refused.
## Caps
`dailySpendCapCents` limits each agent per day: checked before create, and the agent's briqs stop
when it is crossed. From the next UTC day they are asleep, and the next use wakes them. See [Budgets](https://briq.cloud/docs/guides/budgets).
## Where you see it
* Every API response about a briq: `costCentsSoFar` and `sleepsAt`.
* Every MCP result about a briq: `cost so far … · sleeps at HH:MM UTC unless used` (or
`· always on`).
* `briq_quota` / `GET /v1/quota`: the agent's remaining daily spend and the team's balance.
* The dashboard: spend today, credits left, usage per team.
If briq itself has an outage, you are not billed for it: a briq is never billed past its sleep
time (its last recorded use plus its `sleep` window), or past the moment its machine stopped.
---
# Security
URL: https://briq.cloud/docs/security
> Isolation model, what briq can see, abuse policy and responsible disclosure.
## Isolation
* **One microVM per briq.** Firecracker microVMs, not containers on a shared kernel. Two customers
never share a machine.
* **One private network per team.** Nothing resolves across teams.
* **Private by default.** No inbound traffic reaches a briq until you publish it (`expose` on
`briq_run`, or `briq_expose`).
* **Databases from outside over TLS only.** A TCP endpoint takes TLS 1.2 or later and refuses
plaintext. Its password is the gate: recipes generate about 140 bits, the edge refuses a
Postgres, Redis or MongoDB that lets anyone in, limits connections, and locks out an address
after 10 failed logins.
* **Egress is open**, except outbound mail (SMTP ports 25, 465, 587), which the
[abuse policy](#abuse-policy) forbids.
Where data sits and who the sub-processors are: [data protection](https://briq.cloud/legal/data-protection).
## What briq stores
| Stored | Not stored |
| ------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| Image references, ports, sizes, lifetimes | Your image contents |
| Env values; secrets encrypted, and masked in status, logs and audit | `briq_exec` output, beyond the response to you |
| Audit rows: credential, action, target, duration, client name and version; env names, files by path and size, an exec's stdin by size | Env values, file contents, stdin and passwords in commands, in the audit log |
| Logs, boot files and the briq's disk (volume and the rest) while the briq exists | Logs after destroy |
| | Disk contents after destroy; secrets and boot files a day after it |
API keys are stored hashed. Signed-in MCP clients get 30-day access tokens bound to
`https://api.briq.cloud/mcp` and a rotating refresh token; revoking the agent ends both at once,
since every call checks the agent is still connected. No client
gets a token without a person approving it. briq operators can access infrastructure consoles and
machine metadata to run the service; that access is logged.
## Guardrails against runaway agents
* Policy checks (concurrency, size, registry, sleep, daily cap, credits) run **before** any machine
is created.
* Only a signed-in person creates keys or changes a policy; an agent cannot raise its own budget.
* Briqs unused for their `sleep` window go to sleep, and briqs past their agent's daily cap are
stopped, within seconds.
* Machines are created and destroyed in the background, so a dropped connection never leaves one
running untracked.
* Rate limits per credential on requests, creations and exec.
## Abuse policy
briq is for running software an agent or a developer is working on. Not for crypto mining, sending
unsolicited mail, scanning or attacking networks, hosting content illegal in the EU, or evading
another tenant's isolation.
Briqs that break this policy are stopped and the team is contacted; repeated or serious abuse
closes the account. Report abuse to [abuse@briq.cloud](mailto:abuse@briq.cloud).
## Responsible disclosure
Email [security@briq.cloud](mailto:security@briq.cloud) with steps to reproduce and, if relevant,
the team or briq ids. We acknowledge within two business days, keep you informed while we fix it,
and credit you if you want. Do not access other customers' data or run denial-of-service tests.
---
# Regions
URL: https://briq.cloud/docs/regions
> Where briqs run and how a team picks its region.
Each **team** has a region, chosen at creation and changeable in Settings. A briq runs in its
team's region at the time it is created and stays there; changing the region affects new briqs
only.
| Region | Zone | Data stays in the EU |
| ----------------- | ------------- | -------------------- |
| `paris` (default) | Europe | yes |
| `virginia` | North America | no |
| `singapore` | Asia-Pacific | no |
Region ids are stable. `GET /v1/me` returns the regions on offer.
Prices, endpoints and lifetimes are the same everywhere. The team's private network spans regions:
a database in Paris and a worker in Singapore reach each other.
---
# PostgreSQL recipe
URL: https://briq.cloud/cookbook/postgres
> A PostgreSQL database with a persistent volume. Optional pgvector.
Tags: database, sql
Guides:
- [Give Claude Code a database](https://briq.cloud/docs/guides/give-claude-code-a-database.md): Let the agent run migrations, seed data and test queries against a real Postgres.
- [Run tests against real services](https://briq.cloud/docs/guides/run-tests-against-real-services.md): Replace mocks with a real Postgres and Redis for the duration of a test run.
- [Connect to a database from outside](https://briq.cloud/docs/guides/connect-to-a-database-from-outside.md): A briq's database reachable from psql, a BI tool or an app elsewhere, over TLS, with a normal connection string.
## Run it
MCP:
```ts
briq_run({
recipe: "postgres",
params: {
"version": "16",
"extensions": [],
"size": "small",
"diskGb": 2
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "postgres",
"params": {
"version": "16",
"extensions": [],
"size": "small",
"diskGb": 2
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "DATABASE_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `version` | enum | 15, 16, 17 | "16" | — |
| `extensions` | enum[] | pgvector | [] | — |
| `size` | enum | nano, small, medium, large | "small" | — |
| `diskGb` | number | — | 2 | Volume size, in GB |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `DATABASE_URL` | `postgres://postgres:@db..internal:5432/app` |
| `PGHOST` | `db..internal` |
| `PGPORT` | `5432` |
| `PGUSER` | `postgres` |
| `PGPASSWORD` | `` |
| `PGDATABASE` | `app` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| db | `postgres:16` | 5432 | small | 2 GB at /var/lib/postgresql/data |
## When to use it
* Migrations, seeds or an ORM schema need a real database to be checked against.
* An integration suite expects `DATABASE_URL` and you want neither mocks nor Docker.
* Vector search: `extensions: ["pgvector"]` switches to the `pgvector/pgvector` image.
## Tips
* **Run SQL inside the briq.** `DATABASE_URL` is private: `briq_files_put` a file, then
`briq_exec` with `psql -U postgres -d app -v ON_ERROR_STOP=1 -f /file.sql`.
* **`nano`** is enough for schema checks and small fixtures.
* **Data survives stops**, so keep the briq while iterating and destroy it at the end.
* **From another briq**, use `DATABASE_URL` as is.
* **Connect from outside**: `briq_expose` port 5432 with `protocol: "postgres"` gives a connection
string over TLS, for psql or a BI tool. See [Connect to a database from outside](https://briq.cloud/docs/guides/connect-to-a-database-from-outside).
* **No TLS inside the stack**: the connection stays on the stack's private network. An app set up
to require SSL (`sslmode=require`, or settings written for a hosting platform, such as
`ssl_require=True` in Django) refuses to connect: turn that requirement off in the app's settings.
* **Need a bigger database?** The volume starts small: pass `diskGb`, e.g. `params: { diskGb: 20 }`.
Set it when the briq is created, and it counts toward your [plan's disk](https://briq.cloud/docs/cost#plans).
---
# MySQL recipe
URL: https://briq.cloud/cookbook/mysql
> A MySQL database with a persistent volume.
Tags: database, sql
Guide:
- [Connect to a database from outside](https://briq.cloud/docs/guides/connect-to-a-database-from-outside.md): A briq's database reachable from psql, a BI tool or an app elsewhere, over TLS, with a normal connection string.
## Run it
MCP:
```ts
briq_run({
recipe: "mysql",
params: {
"version": "8.4",
"database": "app",
"size": "small",
"diskGb": 2
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "mysql",
"params": {
"version": "8.4",
"database": "app",
"size": "small",
"diskGb": 2
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "DATABASE_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `version` | enum | 8.0, 8.4, 9 | "8.4" | — |
| `database` | string | — | "app" | — |
| `size` | enum | nano, small, medium, large | "small" | — |
| `diskGb` | number | — | 2 | Volume size, in GB |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `DATABASE_URL` | `mysql://root:@mysql..internal:3306/app` |
| `MYSQL_HOST` | `mysql..internal` |
| `MYSQL_PORT` | `3306` |
| `MYSQL_USER` | `root` |
| `MYSQL_PASSWORD` | `` |
| `MYSQL_DATABASE` | `app` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| mysql | `mysql:8.4` | 3306 | small | 2 GB at /var/lib/mysql |
## When to use it
* Your app targets MySQL or MariaDB and migrations must be checked against the real dialect.
* A test suite expects a `mysql://` `DATABASE_URL`.
## Tips
* **First boot is slow**: MySQL initialises its data directory, so `briq_run` can take 30 to 60
seconds. Later starts are fast.
* **Root only**, with a generated password (`MYSQL_ROOT_PASSWORD` inside the briq). Create
least-privilege users with `briq_exec`:
`sh -c 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "create user …"'`.
* **Import a dump**: `briq_files_put` it to `/dump.sql`, then `briq_exec` with
`sh -c 'mysql -uroot -p"$MYSQL_ROOT_PASSWORD" app < /dump.sql'`.
* **Connect from outside**: `briq_expose` port 3306 with `protocol: "mysql"`. The `mysql` CLI
needs 8.1 or later and `--tls-sni-servername`. See [Connect to a database from outside](https://briq.cloud/docs/guides/connect-to-a-database-from-outside).
* **Bigger dataset?** The volume starts small: pass `diskGb`, e.g. `params: { diskGb: 20 }`. Set it
when the briq is created, and it counts toward your [plan's disk](https://briq.cloud/docs/cost#plans).
---
# Redis recipe
URL: https://briq.cloud/cookbook/redis
> A Redis server (Valkey-compatible) for caches and queues.
Tags: cache, queue
Guides:
- [Run tests against real services](https://briq.cloud/docs/guides/run-tests-against-real-services.md): Replace mocks with a real Postgres and Redis for the duration of a test run.
- [Connect to a database from outside](https://briq.cloud/docs/guides/connect-to-a-database-from-outside.md): A briq's database reachable from psql, a BI tool or an app elsewhere, over TLS, with a normal connection string.
## Run it
MCP:
```ts
briq_run({
recipe: "redis",
params: {
"version": "7",
"size": "nano"
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "redis",
"params": {
"version": "7",
"size": "nano"
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "REDIS_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `version` | enum | 7 | "7" | — |
| `size` | enum | nano, small, medium, large | "nano" | — |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `REDIS_URL` | `redis://default:@redis..internal:6379` |
| `REDIS_PASSWORD` | `` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| redis | `redis:7-alpine` | 6379 | nano | — |
## When to use it
* Your app or worker expects `REDIS_URL`: caching, sessions, rate limiting, queues.
* You are testing BullMQ, Sidekiq-style or Celery-style workers against a real broker.
## Tips
* **A password, no volume.** `REDIS_URL` carries the password. Redis saves to its disk when it
stops, so data usually survives a stop, but keep nothing there you cannot rebuild.
* **Pair it with the app in one stack** and pass `REDIS_URL` to it.
* **Inspect it** with `briq_exec`: `["sh", "-c", "REDISCLI_AUTH=$REDIS_PASSWORD redis-cli info memory"]`.
* **Connect from outside**: `briq_expose` port 6379 with `protocol: "redis"` gives a `rediss://`
URL. `redis-cli` needs `--tls --sni `. See [Connect to a database from outside](https://briq.cloud/docs/guides/connect-to-a-database-from-outside).
* **Queues with a UI**: [`redis-bullmq`](https://briq.cloud/cookbook/redis-bullmq).
---
# MongoDB recipe
URL: https://briq.cloud/cookbook/mongo
> A MongoDB server with authentication and a persistent volume.
Tags: database, document
Guide:
- [Connect to a database from outside](https://briq.cloud/docs/guides/connect-to-a-database-from-outside.md): A briq's database reachable from psql, a BI tool or an app elsewhere, over TLS, with a normal connection string.
## Run it
MCP:
```ts
briq_run({
recipe: "mongo",
params: {
"version": "8",
"size": "small",
"diskGb": 2
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "mongo",
"params": {
"version": "8",
"size": "small",
"diskGb": 2
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "MONGODB_URI": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `version` | enum | 7, 8 | "8" | — |
| `size` | enum | nano, small, medium, large | "small" | — |
| `diskGb` | number | — | 2 | Volume size, in GB |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `MONGODB_URI` | `mongodb://root:@mongo..internal:27017/app?authSource=admin` |
| `MONGO_HOST` | `mongo..internal` |
| `MONGO_USER` | `root` |
| `MONGO_PASSWORD` | `` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| mongo | `mongo:8` | 27017 | small | 2 GB at /data/db |
## When to use it
* Your code uses Mongoose, Prisma with MongoDB or the native driver, and needs the real server:
indexes, aggregation, validation.
* Tests expect `MONGODB_URI`.
## Tips
* **Auth is on**: the URI carries the generated root password and `authSource=admin`.
* **No transactions**: it is a single node, not a replica set, so `session.startTransaction()`
fails.
* **One database per suite** when several run in parallel against the same briq.
* **Seed with mongosh**: `briq_files_put` a script to `/seed.js`, then `briq_exec` with
`sh -c 'mongosh -u root -p "$MONGO_INITDB_ROOT_PASSWORD" app /seed.js'`.
* **Connect from outside**: `briq_expose` port 27017 with `protocol: "mongodb"`, for mongosh or
Compass. See [Connect to a database from outside](https://briq.cloud/docs/guides/connect-to-a-database-from-outside).
* **Bigger dataset?** The volume starts small: pass `diskGb`, e.g. `params: { diskGb: 20 }`. Set it
when the briq is created, and it counts toward your [plan's disk](https://briq.cloud/docs/cost#plans).
---
# MinIO (S3) recipe
URL: https://briq.cloud/cookbook/minio
> S3-compatible object storage with a web console.
Tags: storage, s3
## Run it
MCP:
```ts
briq_run({
recipe: "minio",
params: {
"bucket": "app",
"size": "small",
"diskGb": 5
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "minio",
"params": {
"bucket": "app",
"size": "small",
"diskGb": 5
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "S3_ENDPOINT": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `bucket` | string | — | "app" | — |
| `size` | enum | nano, small, medium, large | "small" | — |
| `diskGb` | number | — | 5 | Volume size, in GB |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `S3_ENDPOINT` | `http://minio..internal:9000` |
| `S3_ACCESS_KEY_ID` | `minio` |
| `S3_SECRET_ACCESS_KEY` | `` |
| `S3_BUCKET` | `app` |
| `S3_REGION` | `us-east-1` |
| `MINIO_CONSOLE` | `http://minio..internal:9001` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| minio | `pgsty/minio:RELEASE.2026-08-04T00-00-00Z` | 9000, 9001 | small | 5 GB at /data |
## When to use it
* Your code uploads to S3 and you want a real bucket without AWS credentials.
* Presigned URLs, multipart uploads or bucket policies must behave like S3.
The `bucket` is created at boot. Outputs follow AWS SDK naming.
## Tips
* **Path style**: set `forcePathStyle: true` (AWS SDK v3) or `s3ForcePathStyle` (v2).
* **Region** `us-east-1`, as in the outputs.
* **Console for a human**: `briq_run({ recipe: "minio", expose: "private" })` returns its URL.
* **Presigned URLs** carry the private host. If a browser must use them, expose port 9000 instead
of the console and sign against that URL: a briq has one URL, and moving it to another port
restarts the briq.
* **Image**: [`pgsty/minio`](https://hub.docker.com/r/pgsty/minio), the maintained community build,
since MinIO stopped publishing community images.
* **More storage**: the volume starts small; pass `diskGb`, e.g. `params: { diskGb: 50 }`. Set it
when the briq is created, and it counts toward your [plan's disk](https://briq.cloud/docs/cost#plans).
---
# Mailpit recipe
URL: https://briq.cloud/cookbook/mailpit
> Catches outgoing email for tests, with a web inbox and a JSON API.
Tags: email, testing
## Run it
MCP:
```ts
briq_run({
recipe: "mailpit",
params: {
"size": "nano"
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "mailpit",
"params": {
"size": "nano"
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "SMTP_HOST": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `size` | enum | nano, small | "nano" | — |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `SMTP_HOST` | `mailpit..internal` |
| `SMTP_PORT` | `1025` |
| `SMTP_URL` | `smtp://mailpit..internal:1025` |
| `MAILPIT_UI` | `http://mailpit..internal:8025` |
| `MAILPIT_API` | `http://mailpit..internal:8025/api/v1/messages` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| mailpit | `axllent/mailpit:latest` | 1025, 8025 | nano | — |
## When to use it
* Your tests must assert on the emails your app sends: recipients, subject, body, attachments.
* You want to see what a flow sends without sending anything real.
Point the app at `SMTP_HOST`/`SMTP_PORT` (no auth, no TLS).
## Tips
* **Assert through the API** at `MAILPIT_API`: search with
`/api/v1/search?query=to:alice@example.com`, read one message at `/api/v1/message/`.
* **Clear between tests**: `DELETE` on `MAILPIT_API`.
* **Inbox for a human**: `briq_run({ recipe: "mailpit", expose: "private" })`.
---
# RabbitMQ recipe
URL: https://briq.cloud/cookbook/rabbitmq
> AMQP message broker with the management UI enabled.
Tags: queue, messaging
Guide:
- [Connect to a database from outside](https://briq.cloud/docs/guides/connect-to-a-database-from-outside.md): A briq's database reachable from psql, a BI tool or an app elsewhere, over TLS, with a normal connection string.
## Run it
MCP:
```ts
briq_run({
recipe: "rabbitmq",
params: {
"version": "4",
"size": "small",
"diskGb": 1
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "rabbitmq",
"params": {
"version": "4",
"size": "small",
"diskGb": 1
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "AMQP_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `version` | enum | 3.13, 4 | "4" | — |
| `size` | enum | nano, small, medium, large | "small" | — |
| `diskGb` | number | — | 1 | Volume size, in GB |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `AMQP_URL` | `amqp://app:@rabbitmq..internal:5672` |
| `RABBITMQ_MANAGEMENT` | `http://rabbitmq..internal:15672` |
| `RABBITMQ_USER` | `app` |
| `RABBITMQ_PASSWORD` | `` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| rabbitmq | `rabbitmq:4-management-alpine` | 5672, 15672 | small | 1 GB at /var/lib/rabbitmq |
## When to use it
* Your services speak AMQP (Celery, MassTransit, amqplib, Spring AMQP) and need real acks,
prefetch and dead-lettering.
* You want the management UI or HTTP API to inspect queues during a test.
## Tips
* **Boot takes 30 to 60 seconds** on `small`; `briq_run` waits for it.
* **Declare exchanges and queues from code**, so tests see what production sees.
* **Inspect queues**: `briq_exec` with `["rabbitmqctl", "list_queues", "name", "messages"]`.
* **Workers outside briq**: `briq_expose` port 5672 with `protocol: "amqp"` gives an `amqps://`
URL. See [Connect to a database from outside](https://briq.cloud/docs/guides/connect-to-a-database-from-outside).
* **Management UI for a human**: `briq_run({ recipe: "rabbitmq", expose: "private" })`.
* **Long queues**: messages that outgrow memory go to the volume, which starts small; pass `diskGb`
for more. Set it when the briq is created, and it counts toward your [plan's
disk](https://briq.cloud/docs/cost#plans).
---
# Headless Chrome recipe
URL: https://briq.cloud/cookbook/chrome
> A headless Chromium with a WebSocket endpoint for Playwright or Puppeteer.
Tags: browser, testing
## Run it
MCP:
```ts
briq_run({
recipe: "chrome",
params: {
"size": "small"
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "chrome",
"params": {
"size": "small"
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "BROWSER_WS_ENDPOINT": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `size` | enum | small, medium, large | "small" | — |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `BROWSER_WS_ENDPOINT` | `ws://chrome..internal:3000?token=` |
| `BROWSERLESS_URL` | `http://chrome..internal:3000` |
| `BROWSERLESS_TOKEN` | `` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| chrome | `ghcr.io/browserless/chromium:latest` | 3000 | small | — |
## When to use it
* Tests or the agent need a real browser: Playwright, Puppeteer, PDFs, screenshots.
* You do not want Chromium where the agent runs.
Connect with `chromium.connect(BROWSER_WS_ENDPOINT)` (Playwright) or
`puppeteer.connect({ browserWSEndpoint })`.
## Tips
* **CPU hungry**: `small` handles a few pages; use `medium` or `large` for parallel tests.
Concurrency is 4.
* **From outside briq**: `briq_expose` port 3000. The endpoint's own `token` query parameter is
required either way. With `mode: "private"`, send the URL's token as a cookie
(`headers: { cookie: "briq_token=…" }` in `connect`): a WebSocket client does not follow the
redirect that turns `?briq_token=` into one.
* **HTTP helpers**: `/screenshot`, `/pdf` and `/content` on the same port.
* **No sessions, proxies or stealth**: it is a browser, not a browser platform.
---
# Redis + BullMQ dashboard recipe
URL: https://briq.cloud/cookbook/redis-bullmq
> Redis for BullMQ queues, plus a Bull Board UI to inspect jobs. Point your workers at REDIS_URL; the dashboard discovers the queues itself.
Tags: queue, cache, stack
## Run it
MCP:
```ts
briq_run({
recipe: "redis-bullmq",
params: {
"queues": [
"default"
],
"size": "nano"
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "redis-bullmq",
"params": {
"queues": [
"default"
],
"size": "nano"
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "REDIS_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `queues` | string[] | — | ["default"] | — |
| `size` | enum | nano, small, medium | "nano" | — |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `REDIS_URL` | `redis://redis..internal:6379` |
| `BULL_BOARD_URL` | `http://bullboard..internal:3000` |
| `QUEUES` | `default` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| redis | `redis:7-alpine` | 6379 | nano | — |
| bullboard | `ghcr.io/felixmosh/bull-board:9.10.1` | 3000 | nano | — |
## When to use it
* Your app runs BullMQ (or Bull) workers and you want the queues *and* a way to see them.
* The agent is building or debugging a job pipeline and needs to see waiting, active, failed and
completed jobs.
Workers connect to `REDIS_URL`; Bull Board (`bullboard`) lists each queue once a worker touches it.
## Tips
* **An empty board** means nothing has been enqueued yet. `queues` only echoes the names back in
the outputs.
* **Show the board**: `briq_run({ recipe: "redis-bullmq", expose: "private" })`, or
`briq_expose` port 3000 of `bullboard` with `mode: "private"`.
* **Without the UI**: `briq_exec` on `redis` with `redis-cli llen bull:emails:wait`.
* **The prefix is `bull`.** For another one, run the Bull Board image yourself.
* **No volume**: Redis saves to its disk when it stops, so queues usually survive a stop; keep
nothing there you cannot rebuild.
---
# Neo4j recipe
URL: https://briq.cloud/cookbook/neo4j
> A graph database with a persistent volume, for data an agent should query, not paraphrase.
Tags: database, graph
Guide:
- [Connect to a database from outside](https://briq.cloud/docs/guides/connect-to-a-database-from-outside.md): A briq's database reachable from psql, a BI tool or an app elsewhere, over TLS, with a normal connection string.
## Run it
MCP:
```ts
briq_run({
recipe: "neo4j",
params: {
"version": "5",
"size": "small",
"diskGb": 2
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "neo4j",
"params": {
"version": "5",
"size": "small",
"diskGb": 2
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "NEO4J_BOLT_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `version` | enum | 5 | "5" | — |
| `size` | enum | nano, small, medium, large | "small" | — |
| `diskGb` | number | — | 2 | Volume size, in GB |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `NEO4J_BOLT_URL` | `bolt://neo4j..internal:7687` |
| `NEO4J_HTTP_URL` | `http://neo4j..internal:7474` |
| `NEO4J_USER` | `neo4j` |
| `NEO4J_PASSWORD` | `` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| neo4j | `neo4j:5` | 7474, 7687 | small | 2 GB at /data |
## When to use it
* The agent's memory is relationships: which service calls which, which bug hit which customer.
A graph answers "what is connected to this?" directly.
* The agent should write facts in Cypher as it learns them, and query them later.
* You are prototyping a recommendation, fraud or dependency-graph feature and need a real Bolt
endpoint.
## Tips
* **Auth is on**: user `neo4j`, password `NEO4J_PASSWORD` in the outputs.
* **Connect from outside**: `briq_expose` port 7687 with `protocol: "bolt"` gives a `neo4j+s://`
address. See [Connect to a database from outside](https://briq.cloud/docs/guides/connect-to-a-database-from-outside).
* **Bolt** (`NEO4J_BOLT_URL`) works with the official drivers, or `cypher-shell` via `briq_exec`.
* **Browser for a human**: `briq_expose` port 7474 with `mode: "private"` (the briq restarts to
publish it), and port 7687 with `protocol: "bolt"`. In the Browser, connect to the `neo4j+s://`
address as `neo4j`.
* **Bigger graph?** The volume starts small: pass `diskGb`, e.g. `params: { diskGb: 20 }`. Set it
when the briq is created, and it counts toward your [plan's disk](https://briq.cloud/docs/cost#plans).
---
# Pandoc recipe
URL: https://briq.cloud/cookbook/pandoc
> A document converter with LaTeX, for a skill that has to produce a file, not just a plan for one.
Tags: document, testing
## Run it
MCP:
```ts
briq_run({
recipe: "pandoc",
params: {
"size": "small",
"diskGb": 1
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "pandoc",
"params": {
"size": "small",
"diskGb": 1
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "PANDOC_HOST": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `size` | enum | small, medium, large | "small" | — |
| `diskGb` | number | — | 1 | Volume size, in GB |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `PANDOC_HOST` | `pandoc..internal` |
| `WORKDIR` | `/work` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| pandoc | `pandoc/latex:latest` | — | small | 1 GB at /work |
## When to use it
* The agent must produce a PDF, a DOCX or a deck and has nothing to convert with.
* You want LaTeX-quality typesetting, not a browser's print-to-PDF.
* Many conversions in one session, without a cold start each time.
## Tips
* **Files in and out**: `briq_files_put` to `/work/input.md`, `briq_exec` with
`pandoc /work/input.md -o /work/output.pdf`, then `briq_files_get` `/work/output.pdf`.
* **Unicode or custom fonts**: add `--pdf-engine=xelatex`.
* **No ports**: everything goes through `briq_exec` and the file tools.
* **Large inputs**: `/work` is a volume that starts small; pass `diskGb` for more. Set it when the
briq is created, and it counts toward your [plan's disk](https://briq.cloud/docs/cost#plans).
---
# Plane recipe
URL: https://briq.cloud/cookbook/plane
> A self-hosted Linear/Jira-like board the agent can update, with a link to share.
Tags: app, stack
## Run it
MCP:
```ts
briq_run({
recipe: "plane",
params: {
"size": "small",
"diskGb": 5
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "plane",
"params": {
"size": "small",
"diskGb": 5
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "PLANE_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `domain` | string | — | — | — |
| `size` | enum | small, medium | "small" | — |
| `diskGb` | number | — | 5 | Upload storage (minio) volume size, in GB |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `PLANE_URL` | `http://plane..internal` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| postgres | `postgres:16` | 5432 | nano | 2 GB at /var/lib/postgresql/data |
| redis | `redis:7-alpine` | 6379 | nano | — |
| rabbitmq | `rabbitmq:4-alpine` | 5672 | nano | — |
| minio | `pgsty/minio:RELEASE.2026-08-04T00-00-00Z` | 9000 | nano | 5 GB at /data |
| plane | `makeplane/plane-aio-community:stable` | 80 | small | — |
## When to use it
* The agent works off a PLAN.md only it reads, and you want a board you can watch.
* The agent should file an issue per step, move it as it finishes and comment on what it found.
* You want to send someone a link to where things stand.
Five briqs in one call: Plane, plus the Postgres, Redis, RabbitMQ and MinIO it needs.
## Tips
* **Publish it as you run it**: `briq_run({ recipe: "plane", expose: "private" })`. Plane bakes
its domain into its links at boot, and briq gives it the URL's host. Set `domain` only for
another host.
* **First boot takes about a minute** while Plane migrates its database.
* **Expose only `plane`.** Its Postgres, Redis and RabbitMQ have no password.
* **The agent uses Plane's REST API** with an API key, once someone has signed in and created the
first workspace.
* **Uploads**: `diskGb` sizes the file storage, which starts small; the database keeps its own
small volume. Set it when the stack is created; it counts toward your
[plan's disk](https://briq.cloud/docs/cost#plans).
---
# Qdrant recipe
URL: https://briq.cloud/cookbook/qdrant
> A vector database, for a knowledge file the agent can search by meaning, not grep.
Tags: database, vector, ai
Guide:
- [Connect to a database from outside](https://briq.cloud/docs/guides/connect-to-a-database-from-outside.md): A briq's database reachable from psql, a BI tool or an app elsewhere, over TLS, with a normal connection string.
## Run it
MCP:
```ts
briq_run({
recipe: "qdrant",
params: {
"size": "small",
"diskGb": 2
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "qdrant",
"params": {
"size": "small",
"diskGb": 2
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "QDRANT_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `size` | enum | nano, small, medium, large | "small" | — |
| `diskGb` | number | — | 2 | Volume size, in GB |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `QDRANT_URL` | `http://qdrant..internal:6333` |
| `QDRANT_GRPC_URL` | `http://qdrant..internal:6334` |
| `QDRANT_API_KEY` | `` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| qdrant | `qdrant/qdrant:latest` | 6333, 6334 | small | 2 GB at /qdrant/storage |
## When to use it
* The agent's context is a growing pile of documents or past runs, and keyword search misses what
is phrased differently.
* You are building or testing RAG and need real upsert, filtering and nearest-neighbour search.
* The agent should store what it learns and query it back by meaning.
## Tips
* **Send the API key** on every request: `api-key: `.
* **gRPC for bulk upserts** (`QDRANT_GRPC_URL`); REST (`QDRANT_URL`) for queries.
* **gRPC from outside**: `briq_expose` port 6334 with `protocol: "grpc"`, then send the API key.
See [Connect to a database from outside](https://briq.cloud/docs/guides/connect-to-a-database-from-outside).
* **Create collections first**: `PUT /collections/` with the vector size and distance.
* **Dashboard**: `briq_expose` port 6333 with `mode: "private"` (the briq restarts to publish it),
then open `/dashboard`.
* **Many vectors?** The volume starts small: pass `diskGb`, e.g. `params: { diskGb: 20 }`. Set it
when the briq is created, and it counts toward your [plan's disk](https://briq.cloud/docs/cost#plans).
---
# Wiki.js recipe
URL: https://briq.cloud/cookbook/wiki
> A wiki the agent can write pages to and hand you a link into, instead of NOTES.md.
Tags: app, document, stack
## Run it
MCP:
```ts
briq_run({
recipe: "wiki",
params: {
"size": "small",
"diskGb": 2
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "wiki",
"params": {
"size": "small",
"diskGb": 2
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "WIKI_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `size` | enum | small, medium | "small" | — |
| `diskGb` | number | — | 2 | Volume size, in GB |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `WIKI_URL` | `http://wiki..internal:3000` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| postgres | `postgres:16` | 5432 | nano | 2 GB at /var/lib/postgresql/data |
| wiki | `requarks/wiki:2` | 3000 | small | — |
## When to use it
* Your repo has grown NOTES.md and one-off write-ups that nobody opens.
* The agent should write up an incident, a decision or a runbook as a page with a URL.
* You want to send a link to a page with search and history, not a markdown diff.
Two briqs: `wiki` serves it, `postgres` stores it.
## Tips
* **Expose only `wiki`**: `briq_run({ recipe: "wiki", expose: "private" })`.
* **Create the admin account** in the UI on the first visit, then an API token in the admin area.
* **The agent writes pages** through the GraphQL API with that token.
* **Content survives stops**, so keep the briqs between sessions.
* **Many pages and uploads**: the database volume starts small; pass `diskGb` for more. Set it when
the briq is created, and it counts toward your [plan's disk](https://briq.cloud/docs/cost#plans).
---
# Grafana recipe
URL: https://briq.cloud/cookbook/grafana
> A dashboard the agent can point at its own data, instead of a STATUS.md it writes by hand.
Tags: app, observability
## Run it
MCP:
```ts
briq_run({
recipe: "grafana",
params: {
"size": "small",
"diskGb": 1
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "grafana",
"params": {
"size": "small",
"diskGb": 1
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "GRAFANA_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `size` | enum | nano, small, medium | "small" | — |
| `diskGb` | number | — | 1 | Volume size, in GB |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `GRAFANA_URL` | `http://grafana..internal:3000` |
| `GRAFANA_ADMIN_USER` | `admin` |
| `GRAFANA_ADMIN_PASSWORD` | `` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| grafana | `grafana/grafana:latest` | 3000 | small | 1 GB at /var/lib/grafana |
## When to use it
* The agent reports a load test or a long run as a paragraph of numbers, and you would rather see
a chart.
* You want dashboards over data the agent's briqs already produce: Postgres, a Prometheus
endpoint, logs.
* You want to hand someone a live dashboard instead of a note that goes stale.
## Tips
* **Wire it from the API**: `POST /api/datasources` on `GRAFANA_URL` with basic auth
(`GRAFANA_ADMIN_USER`, `GRAFANA_ADMIN_PASSWORD`).
* **Data sources in the same stack** stay private; only Grafana needs a URL.
* **Dashboards as JSON**: `POST /api/dashboards/db` beats building panels by hand.
* **Share it**: `briq_run({ recipe: "grafana", expose: "private" })`, or `briq_expose` port 3000
with `mode: "private"`.
* **More room**: the volume starts small; pass `diskGb` for more. Set it when the briq is created,
and it counts toward your [plan's disk](https://briq.cloud/docs/cost#plans).
---
# Metabase recipe
URL: https://briq.cloud/cookbook/metabase
> Reports on a Postgres warehouse: load a dataset, build a dashboard, share a link to it.
Tags: app, analytics, stack
Guide:
- [Report on a dataset](https://briq.cloud/docs/guides/report-on-a-dataset.md): Load a public dataset into Postgres, chart it in Metabase, and share a link to the dashboard.
## Run it
MCP:
```ts
briq_run({
recipe: "metabase",
params: {
"size": "small",
"dbSize": "nano"
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "metabase",
"params": {
"size": "small",
"dbSize": "nano"
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "METABASE_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `size` | enum | small, medium | "small" | Metabase |
| `dbSize` | enum | nano, small, medium | "nano" | The warehouse: small or more for a dataset over a few million rows |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `METABASE_URL` | `http://metabase..internal:3000` |
| `METABASE_ADMIN_EMAIL` | `admin@metabase.local` |
| `METABASE_ADMIN_PASSWORD` | `` |
| `DATABASE_URL` | `postgres://postgres:@postgres..internal:5432/warehouse` |
| `READONLY_DATABASE_URL` | `postgres://reporter:@postgres..internal:5432/warehouse` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| postgres | `postgres:16-alpine` | 5432 | nano | 10 GB at /var/lib/postgresql/data |
| metabase | `metabase/metabase:v0.63.19.2` | 3000 | small | — |
## When to use it
* The agent has analysed a dataset and you would rather open charts than read a table in chat.
* You want a dashboard someone can open from a link, without an account.
* You want SQL questions over data the agent loaded, kept and rerun on fresh data.
Two briqs: `metabase` serves the dashboards, `postgres` is the warehouse it reads. On first boot
Metabase makes its admin account (password in `METABASE_ADMIN_PASSWORD`) and connects the
warehouse as `Warehouse`, read through a read-only role: nobody signed in to Metabase can change
the data. The full walk-through, from a CSV on the web to a shared link, is
[Report on a dataset](https://briq.cloud/docs/guides/report-on-a-dataset).
## Tips
* **Load from inside the warehouse**: the image has `wget`, so
`wget -qO- | psql -U postgres -d warehouse -c "\copy t from stdin with (format csv, header)"`
in `briq_exec` never sends the data through the agent.
* **Tables the agent creates as `postgres` in `public`** are readable by Metabase. Another schema
needs `GRANT USAGE ON SCHEMA s TO reporter; GRANT SELECT ON ALL TABLES IN SCHEMA s TO reporter`.
* **`mb` calls Metabase's API as the admin** from `briq_exec` on the `metabase` briq:
`["mb", "GET", "/api/database"]`; `["mb", "POST", "/api/card", "-"]` with the JSON as `stdin`.
* **Native SQL questions** (`dataset_query.type: "native"`) are the shortest way to a chart. After
loading a new table, `POST /api/database//sync_schema` makes it browsable in the UI too.
* **Share one dashboard**: `POST /api/dashboard//public_link` returns a `uuid`; the page is
`/public/dashboard/` on the briq's URL. Run with `expose: "private"` and keep the
`?briq_token=` on the link you send, so the link is the only way in.
* **First boot takes about three minutes** while Metabase migrates its database: `briq_run` can
answer while `metabase` is still `creating`; `briq_status` says when it runs. Later starts are
faster, and the dashboards survive stops.
* **Our World in Data files**: aggregate rows (World, continents, income groups) have an empty
`iso_code`, not `OWID_WRL`. Match the world on `country = 'World'`; `iso_code IS NOT NULL` keeps
the countries.
---
# Memos recipe
URL: https://briq.cloud/cookbook/memos
> A markdown note store with an API, for memory a human can read and the agent can append to.
Tags: memory, document, app
## Run it
MCP:
```ts
briq_run({
recipe: "memos",
params: {
"size": "nano",
"diskGb": 1
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "memos",
"params": {
"size": "nano",
"diskGb": 1
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "MEMOS_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `size` | enum | nano, small, medium | "nano" | — |
| `diskGb` | number | — | 1 | Volume size, in GB |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `MEMOS_URL` | `http://memos..internal:5230` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| memos | `neosmemo/memos:stable` | 5230 | nano | 1 GB at /var/opt/memos |
## When to use it
* You want the agent's memory readable: one note per fact, with a timestamp, tags and search,
instead of a MEMORY.md it must re-read in full.
* The agent should append as it learns: a note per decision, incident or flaky test.
* You want to skim what it learned from a browser.
For structured recall, pair it with [qdrant](https://briq.cloud/cookbook/qdrant) or [neo4j](https://briq.cloud/cookbook/neo4j).
## Tips
* **Create the first account in the UI**: `briq_expose` port 5230 with `mode: "private"` and visit
it. The first account becomes the admin.
* **The agent writes through the REST API** with an access token from Settings. Tags are `#tag` in
the body.
* **Free between sessions**: a sleeping briq costs nothing, and the next call or visit wakes it in about a second.
* **Attachments**: the volume starts small; pass `diskGb` for more. Set it when the briq is created,
and it counts toward your [plan's disk](https://briq.cloud/docs/cost#plans).
---
# SiYuan recipe
URL: https://briq.cloud/cookbook/siyuan
> A block-based knowledge workspace with a kernel API, for an agent vault a human can browse.
Tags: memory, document, app
## Run it
MCP:
```ts
briq_run({
recipe: "siyuan",
params: {
"size": "small",
"diskGb": 2
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "siyuan",
"params": {
"size": "small",
"diskGb": 2
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "SIYUAN_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `size` | enum | nano, small, medium | "small" | — |
| `diskGb` | number | — | 2 | Volume size, in GB |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `SIYUAN_URL` | `http://siyuan..internal:6806` |
| `SIYUAN_AUTH_CODE` | `` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| siyuan | `b3log/siyuan:latest` | 6806 | small | 2 GB at /siyuan/workspace |
## When to use it
* You like the Obsidian shape (wikilinks, backlinks, a graph of notes) but need it where an agent
can reach it. SiYuan is that, as a server with an API.
* The agent should build a vault over time and walk its links.
* You want to read the same vault in a browser.
Every note is made of blocks with ids, so the agent can insert in the middle of a document.
## Tips
* **The auth code is the API key**: send `Authorization: Token `. It gates the UI
too.
* **Write** with `/api/block/appendBlock`, **read** with `/api/query/sql`: the block tree as SQL.
* **Browse it**: `briq_run({ recipe: "siyuan", expose: "private" })`.
* **Alternatives**: [memos](https://briq.cloud/cookbook/memos) for quick capture, [wiki](https://briq.cloud/cookbook/wiki) for pages
other people read.
* **Assets**: the workspace volume starts small; pass `diskGb` for more. Set it when the briq is
created, and it counts toward your [plan's disk](https://briq.cloud/docs/cost#plans).
---
# Python app recipe
URL: https://briq.cloud/cookbook/python
> Your Python code running as a service, from files or a GitHub repo: it installs requirements.txt and starts it. No image to build.
Tags: app, language
Guides:
- [Run your own app](https://briq.cloud/docs/guides/run-your-own-app.md): Your code as a running service, with a URL, in one call and no image to build.
- [Run a GitHub repo](https://briq.cloud/docs/guides/run-a-github-repo.md): An app from a repo, running with a URL. The briq downloads the code itself, and nothing is built on your side.
## Run it
MCP:
```ts
briq_run({
recipe: "python",
params: {
"version": "3.12",
"packages": [],
"port": 8080,
"env": {},
"size": "small"
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "python",
"params": {
"version": "3.12",
"packages": [],
"port": 8080,
"env": {},
"size": "small"
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "APP_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `version` | enum | 3.12, 3.13, 3.14 | "3.12" | — |
| `files` | record | { "path": "content" \| { base64 } } | — | Your app's files, path → content (text, or { base64 }). Relative paths go under /app. For a bigger app, or one already on GitHub, pass `repo` instead. Without either, a hello-world app. |
| `repo` | object | { url, ref?, dir?, token? } | — | Your code from a repo instead of `files`. url: "github.com/owner/app", or on another host (GitLab, Bitbucket, Codeberg) the https URL of a .tar.gz archive, without ref. ref: a branch, tag or commit sha; default branch; a full sha pins the code. dir: the app's folder, e.g. "backend". token, private repos only: { secret: "GITHUB_TOKEN", value }, a fine-grained token with Contents: read on this repo; never the person's own token. The briq downloads the code itself, installs when a lockfile changed, runs `build` when the commit changed, then `start` |
| `packages` | string[] | — | [] | Extra packages to install at each start, besides your manifest |
| `install` | string | — | — | Shell command replacing the default install step: run before each start; with `repo`, only when a lockfile changed (go and rust build here, at each start) |
| `build` | string | — | — | Shell command run after the install, e.g. "npm run build": with `repo`, only when the commit or the install changed; with files, at each start |
| `start` | string | — | — | Shell command that starts the app (it must not exit). With `repo`, pass it: the default (python app.py, ruby app.rb…) rarely matches a repo; node runs npm start, bun bun run start |
| `port` | number | — | 8080 | — |
| `env` | record | { NAME: "value" \| { secret, value? } } | {} | Env vars. A credential goes as { secret: "NAME", value: "…" }: stored encrypted and never shown again |
| `size` | enum | nano, small, medium, large | "small" | A build (Next.js, Nuxt, a Rust release, a Go toolchain) is many times faster on medium or large: small has one shared CPU, slowed down once a long build used its burst. Up to small, a sleeping briq wakes from a memory snapshot in seconds; medium and large start from scratch on a wake (with `repo`: the branch is looked up again, and a new commit is installed and built before the app answers) |
| `diskGb` | number | — | — | With `repo` only: the size in GB of the volume (/work) that holds the code, its dependencies and build caches |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `APP_URL` | `http://app..internal:8080` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| app | `python:3.12-slim` | 8080 | small | — |
## When to use it
* You wrote a small Flask, FastAPI or plain `http.server` app and want it running next to its
database, with a URL, without building an image.
* A script should run as a service: a webhook receiver, a scheduler, a bot.
## Tips
* **Code in a repo**: pass `repo: { url: "github.com/owner/app" }` instead of `files`. See
[Run a GitHub repo](https://briq.cloud/docs/guides/run-a-github-repo).
* **A bot or a scheduler** that only makes outgoing calls is not seen as use, so it sleeps after
its `sleep` window. Give it `sleep: "never"` (always on, Pro plan and above), or a window longer
than the gap between its runs.
* **Pass the code as `files`**: `{ "app.py": "…", "requirements.txt": "flask\npsycopg[binary]" }`.
Relative paths go under `/app`, the working directory. They are written before the app starts,
and again whenever it starts over.
* **`requirements.txt` is installed at each start**; `packages: ["flask"]` adds more without a
file. The packages stay on the briq's disk, so after the first start the install is quick.
* **`start`** is the command when it is not `python app.py`, e.g.
`"uvicorn main:app --host :: --port 8080"`.
* **Listen on `::` and on `$PORT`** (8080 by default): the private network is IPv6.
* **Wire a database** with `env`: run the [postgres](https://briq.cloud/cookbook/postgres) recipe in the same stack
first and pass its `DATABASE_URL` as a secret, `{ secret: "DATABASE_URL", value: "…" }`.
* **Publish it as you run it**:
`briq_run({ recipe: "python", params: { files }, expose: "private" })` returns `URL` (`"public"`
instead of `"private"` for anyone).
* **If it exits before it answers**, the run fails and the briq is in `error`; `briq_logs` shows
the traceback. `briq_destroy` it, fix the files, and run again. If it exits later, the briq
stops with the code in `lastExit`.
* **Step by step**: [Run your own app](https://briq.cloud/docs/guides/run-your-own-app), with a database and a URL.
---
# Node.js app recipe
URL: https://briq.cloud/cookbook/node
> Your Node.js code running as a service, from files or a GitHub repo: it installs package.json and starts it. No image to build.
Tags: app, language
Guides:
- [Run your own app](https://briq.cloud/docs/guides/run-your-own-app.md): Your code as a running service, with a URL, in one call and no image to build.
- [Run a GitHub repo](https://briq.cloud/docs/guides/run-a-github-repo.md): An app from a repo, running with a URL. The briq downloads the code itself, and nothing is built on your side.
## Run it
MCP:
```ts
briq_run({
recipe: "node",
params: {
"version": "22",
"packages": [],
"port": 8080,
"env": {},
"size": "small"
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "node",
"params": {
"version": "22",
"packages": [],
"port": 8080,
"env": {},
"size": "small"
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "APP_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `version` | enum | 22, 24 | "22" | — |
| `files` | record | { "path": "content" \| { base64 } } | — | Your app's files, path → content (text, or { base64 }). Relative paths go under /app. For a bigger app, or one already on GitHub, pass `repo` instead. Without either, a hello-world app. |
| `repo` | object | { url, ref?, dir?, token? } | — | Your code from a repo instead of `files`. url: "github.com/owner/app", or on another host (GitLab, Bitbucket, Codeberg) the https URL of a .tar.gz archive, without ref. ref: a branch, tag or commit sha; default branch; a full sha pins the code. dir: the app's folder, e.g. "backend". token, private repos only: { secret: "GITHUB_TOKEN", value }, a fine-grained token with Contents: read on this repo; never the person's own token. The briq downloads the code itself, installs when a lockfile changed, runs `build` when the commit changed, then `start` |
| `packages` | string[] | — | [] | Extra packages to install at each start, besides your manifest |
| `install` | string | — | — | Shell command replacing the default install step: run before each start; with `repo`, only when a lockfile changed (go and rust build here, at each start) |
| `build` | string | — | — | Shell command run after the install, e.g. "npm run build": with `repo`, only when the commit or the install changed; with files, at each start |
| `start` | string | — | — | Shell command that starts the app (it must not exit). With `repo`, pass it: the default (python app.py, ruby app.rb…) rarely matches a repo; node runs npm start, bun bun run start |
| `port` | number | — | 8080 | — |
| `env` | record | { NAME: "value" \| { secret, value? } } | {} | Env vars. A credential goes as { secret: "NAME", value: "…" }: stored encrypted and never shown again |
| `size` | enum | nano, small, medium, large | "small" | A build (Next.js, Nuxt, a Rust release, a Go toolchain) is many times faster on medium or large: small has one shared CPU, slowed down once a long build used its burst. Up to small, a sleeping briq wakes from a memory snapshot in seconds; medium and large start from scratch on a wake (with `repo`: the branch is looked up again, and a new commit is installed and built before the app answers) |
| `diskGb` | number | — | — | With `repo` only: the size in GB of the volume (/work) that holds the code, its dependencies and build caches |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `APP_URL` | `http://app..internal:8080` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| app | `node:22-slim` | 8080 | small | — |
## When to use it
* You wrote an Express, Fastify or plain `node:http` server and want it running next to its
database, with a URL, without building an image.
* A webhook receiver, an API mock or a small bot should run as a service.
## Tips
* **Code in a repo**: pass `repo: { url: "github.com/owner/app" }` instead of `files`. See
[Run a GitHub repo](https://briq.cloud/docs/guides/run-a-github-repo).
* **A bot or a scheduler** that only makes outgoing calls is not seen as use, so it sleeps after
its `sleep` window. Give it `sleep: "never"` (always on, Pro plan and above), or a window longer
than the gap between its runs.
* **Pass the code as `files`**: `{ "server.js": "…", "package.json": "…" }`. Relative paths go
under `/app`, the working directory, written before the app starts and again whenever it starts over.
* **`package.json` is installed at each start** (`npm ci` when there is a lockfile);
`packages: ["express"]` adds more without one. They stay on the disk, so restarts are quick.
* **`start`** is the command when it is not `node server.js`, e.g. `"npm start"`.
* **Yarn 2 and later** need the `packageManager` field in `package.json` (`yarn set version`
writes it): without it, corepack runs Yarn 1 instead of the version the repo was made with.
* **Listen on `::` and on `process.env.PORT`** (8080 by default).
* **No build step**: ship JavaScript, or use the [bun](https://briq.cloud/cookbook/bun) recipe to run TypeScript
as it is.
* **Publish it as you run it** with `expose: "private"` (or `"public"` for anyone): it returns `URL`.
* **Step by step**: [Run your own app](https://briq.cloud/docs/guides/run-your-own-app), with a database and a URL.
---
# Bun app recipe
URL: https://briq.cloud/cookbook/bun
> Your TypeScript or JavaScript running on Bun, from files or a GitHub repo: it installs package.json and starts it. No build step.
Tags: app, language
Guides:
- [Run your own app](https://briq.cloud/docs/guides/run-your-own-app.md): Your code as a running service, with a URL, in one call and no image to build.
- [Run a GitHub repo](https://briq.cloud/docs/guides/run-a-github-repo.md): An app from a repo, running with a URL. The briq downloads the code itself, and nothing is built on your side.
## Run it
MCP:
```ts
briq_run({
recipe: "bun",
params: {
"version": "1",
"packages": [],
"port": 8080,
"env": {},
"size": "small"
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "bun",
"params": {
"version": "1",
"packages": [],
"port": 8080,
"env": {},
"size": "small"
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "APP_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `version` | enum | 1 | "1" | — |
| `files` | record | { "path": "content" \| { base64 } } | — | Your app's files, path → content (text, or { base64 }). Relative paths go under /app. For a bigger app, or one already on GitHub, pass `repo` instead. Without either, a hello-world app. |
| `repo` | object | { url, ref?, dir?, token? } | — | Your code from a repo instead of `files`. url: "github.com/owner/app", or on another host (GitLab, Bitbucket, Codeberg) the https URL of a .tar.gz archive, without ref. ref: a branch, tag or commit sha; default branch; a full sha pins the code. dir: the app's folder, e.g. "backend". token, private repos only: { secret: "GITHUB_TOKEN", value }, a fine-grained token with Contents: read on this repo; never the person's own token. The briq downloads the code itself, installs when a lockfile changed, runs `build` when the commit changed, then `start` |
| `packages` | string[] | — | [] | Extra packages to install at each start, besides your manifest |
| `install` | string | — | — | Shell command replacing the default install step: run before each start; with `repo`, only when a lockfile changed (go and rust build here, at each start) |
| `build` | string | — | — | Shell command run after the install, e.g. "npm run build": with `repo`, only when the commit or the install changed; with files, at each start |
| `start` | string | — | — | Shell command that starts the app (it must not exit). With `repo`, pass it: the default (python app.py, ruby app.rb…) rarely matches a repo; node runs npm start, bun bun run start |
| `port` | number | — | 8080 | — |
| `env` | record | { NAME: "value" \| { secret, value? } } | {} | Env vars. A credential goes as { secret: "NAME", value: "…" }: stored encrypted and never shown again |
| `size` | enum | nano, small, medium, large | "small" | A build (Next.js, Nuxt, a Rust release, a Go toolchain) is many times faster on medium or large: small has one shared CPU, slowed down once a long build used its burst. Up to small, a sleeping briq wakes from a memory snapshot in seconds; medium and large start from scratch on a wake (with `repo`: the branch is looked up again, and a new commit is installed and built before the app answers) |
| `diskGb` | number | — | — | With `repo` only: the size in GB of the volume (/work) that holds the code, its dependencies and build caches |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `APP_URL` | `http://app..internal:8080` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| app | `oven/bun:1-slim` | 8080 | small | — |
## When to use it
* You have TypeScript and want it running without a compile step or an image.
* A small API or webhook receiver, where `Bun.serve` is all the framework you need.
## Tips
* **Code in a repo**: pass `repo: { url: "github.com/owner/app" }` instead of `files`. See
[Run a GitHub repo](https://briq.cloud/docs/guides/run-a-github-repo).
* **Pass the code as `files`**: `{ "server.ts": "…", "package.json": "…" }`. Relative paths go
under `/app`, written before the app starts and again whenever it starts over.
* **`package.json` is installed at each start**; `packages: ["hono"]` adds more. They stay on
the disk, so restarts are quick.
* **`start`** is the command when it is not `bun run server.ts`.
* **Listen on `::` and on `process.env.PORT`** (8080 by default): `Bun.serve({ hostname: "::" })`.
* **Publish it as you run it** with `expose: "private"` (or `"public"` for anyone): it returns `URL`.
* **Step by step**: [Run your own app](https://briq.cloud/docs/guides/run-your-own-app), with a database and a URL.
---
# Go app recipe
URL: https://briq.cloud/cookbook/go
> Your Go code running as a service, from files or a GitHub repo: it builds the module and starts the binary. No image to build.
Tags: app, language
Guides:
- [Run your own app](https://briq.cloud/docs/guides/run-your-own-app.md): Your code as a running service, with a URL, in one call and no image to build.
- [Run a GitHub repo](https://briq.cloud/docs/guides/run-a-github-repo.md): An app from a repo, running with a URL. The briq downloads the code itself, and nothing is built on your side.
## Run it
MCP:
```ts
briq_run({
recipe: "go",
params: {
"version": "1.25",
"port": 8080,
"env": {},
"size": "small"
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "go",
"params": {
"version": "1.25",
"port": 8080,
"env": {},
"size": "small"
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "APP_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `version` | enum | 1.25, 1.24 | "1.25" | — |
| `files` | record | { "path": "content" \| { base64 } } | — | Your app's files, path → content (text, or { base64 }). Relative paths go under /app. For a bigger app, or one already on GitHub, pass `repo` instead. Without either, a hello-world app. |
| `repo` | object | { url, ref?, dir?, token? } | — | Your code from a repo instead of `files`. url: "github.com/owner/app", or on another host (GitLab, Bitbucket, Codeberg) the https URL of a .tar.gz archive, without ref. ref: a branch, tag or commit sha; default branch; a full sha pins the code. dir: the app's folder, e.g. "backend". token, private repos only: { secret: "GITHUB_TOKEN", value }, a fine-grained token with Contents: read on this repo; never the person's own token. The briq downloads the code itself, installs when a lockfile changed, runs `build` when the commit changed, then `start` |
| `install` | string | — | — | Shell command replacing the default install step: run before each start; with `repo`, only when a lockfile changed (go and rust build here, at each start) |
| `build` | string | — | — | Shell command run after the install, e.g. "npm run build": with `repo`, only when the commit or the install changed; with files, at each start |
| `start` | string | — | — | Shell command that starts the app (it must not exit). With `repo`, pass it: the default (python app.py, ruby app.rb…) rarely matches a repo; node runs npm start, bun bun run start |
| `port` | number | — | 8080 | — |
| `env` | record | { NAME: "value" \| { secret, value? } } | {} | Env vars. A credential goes as { secret: "NAME", value: "…" }: stored encrypted and never shown again |
| `size` | enum | nano, small, medium, large | "small" | A build (Next.js, Nuxt, a Rust release, a Go toolchain) is many times faster on medium or large: small has one shared CPU, slowed down once a long build used its burst. Up to small, a sleeping briq wakes from a memory snapshot in seconds; medium and large start from scratch on a wake (with `repo`: the branch is looked up again, and a new commit is installed and built before the app answers) |
| `diskGb` | number | — | — | With `repo` only: the size in GB of the volume (/work) that holds the code, its dependencies and build caches |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `APP_URL` | `http://app..internal:8080` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| app | `golang:1.25-alpine` | 8080 | small | — |
## When to use it
* You wrote a Go service and want it built and running next to its database, without a
Dockerfile or a registry.
## Tips
* **Code in a repo**: pass `repo: { url: "github.com/owner/app" }` instead of `files`. See
[Run a GitHub repo](https://briq.cloud/docs/guides/run-a-github-repo).
* **Pass the module as `files`**: `go.mod`, `main.go` and the rest, with relative paths (they go
under `/app`). `go.sum` too when there are dependencies.
* **It builds at each start** (`go build`), then runs the binary. The build cache stays on the
disk, so a restart rebuilds in seconds; the first start downloads modules and takes longer. If
it outlasts `briq_run`'s two minutes, the briq shows `creating` until the build is done:
`briq_status` tells you when it runs.
* **`ListenAndServe(":" + os.Getenv("PORT"), …)`** listens on IPv6 and IPv4; 8080 by default.
* **Publish it as you run it** with `expose: "private"` (or `"public"` for anyone): it returns `URL`.
* **Step by step**: [Run your own app](https://briq.cloud/docs/guides/run-your-own-app), with a database and a URL.
---
# Ruby app recipe
URL: https://briq.cloud/cookbook/ruby
> Your Ruby code running as a service, from files or a GitHub repo: it bundles the Gemfile and starts it. No image to build.
Tags: app, language
Guides:
- [Run your own app](https://briq.cloud/docs/guides/run-your-own-app.md): Your code as a running service, with a URL, in one call and no image to build.
- [Run a GitHub repo](https://briq.cloud/docs/guides/run-a-github-repo.md): An app from a repo, running with a URL. The briq downloads the code itself, and nothing is built on your side.
## Run it
MCP:
```ts
briq_run({
recipe: "ruby",
params: {
"version": "3.4",
"packages": [],
"port": 8080,
"env": {},
"size": "small"
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "ruby",
"params": {
"version": "3.4",
"packages": [],
"port": 8080,
"env": {},
"size": "small"
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "APP_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `version` | enum | 3.4, 3.3 | "3.4" | — |
| `files` | record | { "path": "content" \| { base64 } } | — | Your app's files, path → content (text, or { base64 }). Relative paths go under /app. For a bigger app, or one already on GitHub, pass `repo` instead. Without either, a hello-world app. |
| `repo` | object | { url, ref?, dir?, token? } | — | Your code from a repo instead of `files`. url: "github.com/owner/app", or on another host (GitLab, Bitbucket, Codeberg) the https URL of a .tar.gz archive, without ref. ref: a branch, tag or commit sha; default branch; a full sha pins the code. dir: the app's folder, e.g. "backend". token, private repos only: { secret: "GITHUB_TOKEN", value }, a fine-grained token with Contents: read on this repo; never the person's own token. The briq downloads the code itself, installs when a lockfile changed, runs `build` when the commit changed, then `start` |
| `packages` | string[] | — | [] | Extra packages to install at each start, besides your manifest |
| `install` | string | — | — | Shell command replacing the default install step: run before each start; with `repo`, only when a lockfile changed (go and rust build here, at each start) |
| `build` | string | — | — | Shell command run after the install, e.g. "npm run build": with `repo`, only when the commit or the install changed; with files, at each start |
| `start` | string | — | — | Shell command that starts the app (it must not exit). With `repo`, pass it: the default (python app.py, ruby app.rb…) rarely matches a repo; node runs npm start, bun bun run start |
| `port` | number | — | 8080 | — |
| `env` | record | { NAME: "value" \| { secret, value? } } | {} | Env vars. A credential goes as { secret: "NAME", value: "…" }: stored encrypted and never shown again |
| `size` | enum | nano, small, medium, large | "small" | A build (Next.js, Nuxt, a Rust release, a Go toolchain) is many times faster on medium or large: small has one shared CPU, slowed down once a long build used its burst. Up to small, a sleeping briq wakes from a memory snapshot in seconds; medium and large start from scratch on a wake (with `repo`: the branch is looked up again, and a new commit is installed and built before the app answers) |
| `diskGb` | number | — | — | With `repo` only: the size in GB of the volume (/work) that holds the code, its dependencies and build caches |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `APP_URL` | `http://app..internal:8080` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| app | `ruby:3.4-slim` | 8080 | small | — |
## When to use it
* You wrote a Sinatra, Roda or Rack app and want it running next to its database, without
building an image.
## Tips
* **Code in a repo**: pass `repo: { url: "github.com/owner/app" }` instead of `files`. See
[Run a GitHub repo](https://briq.cloud/docs/guides/run-a-github-repo).
* **Pass the code as `files`**: `{ "app.rb": "…", "Gemfile": "…" }`. Relative paths go under
`/app`, written before the app starts and again whenever it starts over.
* **The `Gemfile` is bundled at each start**; `packages: ["sinatra"]` installs gems without one.
Gems stay on the disk, so restarts are quick.
* **`start`** is the command when it is not `ruby app.rb`, e.g.
`"bundle exec rackup -o :: -p 8080"`.
* **Listen on `::` and on `ENV["PORT"]`** (8080 by default).
* **Publish it as you run it** with `expose: "private"` (or `"public"` for anyone): it returns `URL`.
* **Step by step**: [Run your own app](https://briq.cloud/docs/guides/run-your-own-app), with a database and a URL.
---
# Rust app recipe
URL: https://briq.cloud/cookbook/rust
> Your Rust crate running as a service, from files or a GitHub repo: it builds a release and runs it. No image to build.
Tags: app, language
Guides:
- [Run your own app](https://briq.cloud/docs/guides/run-your-own-app.md): Your code as a running service, with a URL, in one call and no image to build.
- [Run a GitHub repo](https://briq.cloud/docs/guides/run-a-github-repo.md): An app from a repo, running with a URL. The briq downloads the code itself, and nothing is built on your side.
## Run it
MCP:
```ts
briq_run({
recipe: "rust",
params: {
"version": "1",
"port": 8080,
"env": {},
"size": "small"
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "rust",
"params": {
"version": "1",
"port": 8080,
"env": {},
"size": "small"
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "APP_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `version` | enum | 1 | "1" | — |
| `files` | record | { "path": "content" \| { base64 } } | — | Your app's files, path → content (text, or { base64 }). Relative paths go under /app. For a bigger app, or one already on GitHub, pass `repo` instead. Without either, a hello-world app. |
| `repo` | object | { url, ref?, dir?, token? } | — | Your code from a repo instead of `files`. url: "github.com/owner/app", or on another host (GitLab, Bitbucket, Codeberg) the https URL of a .tar.gz archive, without ref. ref: a branch, tag or commit sha; default branch; a full sha pins the code. dir: the app's folder, e.g. "backend". token, private repos only: { secret: "GITHUB_TOKEN", value }, a fine-grained token with Contents: read on this repo; never the person's own token. The briq downloads the code itself, installs when a lockfile changed, runs `build` when the commit changed, then `start` |
| `install` | string | — | — | Shell command replacing the default install step: run before each start; with `repo`, only when a lockfile changed (go and rust build here, at each start) |
| `build` | string | — | — | Shell command run after the install, e.g. "npm run build": with `repo`, only when the commit or the install changed; with files, at each start |
| `start` | string | — | — | Shell command that starts the app (it must not exit). With `repo`, pass it: the default (python app.py, ruby app.rb…) rarely matches a repo; node runs npm start, bun bun run start |
| `port` | number | — | 8080 | — |
| `env` | record | { NAME: "value" \| { secret, value? } } | {} | Env vars. A credential goes as { secret: "NAME", value: "…" }: stored encrypted and never shown again |
| `size` | enum | nano, small, medium, large | "small" | A build (Next.js, Nuxt, a Rust release, a Go toolchain) is many times faster on medium or large: small has one shared CPU, slowed down once a long build used its burst. Up to small, a sleeping briq wakes from a memory snapshot in seconds; medium and large start from scratch on a wake (with `repo`: the branch is looked up again, and a new commit is installed and built before the app answers) |
| `diskGb` | number | — | — | With `repo` only: the size in GB of the volume (/work) that holds the code, its dependencies and build caches |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `APP_URL` | `http://app..internal:8080` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| app | `rust:1-slim` | 8080 | small | — |
## When to use it
* You wrote an Axum, Actix or plain `std::net` service and want it built and running next to its
database, without a Dockerfile or a registry.
## Tips
* **Code in a repo**: pass `repo: { url: "github.com/owner/app" }` instead of `files`. See
[Run a GitHub repo](https://briq.cloud/docs/guides/run-a-github-repo).
* **Pass the crate as `files`**: `Cargo.toml`, `Cargo.lock` and `src/main.rs` (relative paths
go under `/app`).
* **It builds a release at each start**, then `cargo run --release` runs it, whatever the binary
is called. `target/` stays on the briq's disk, so a restart rebuilds in seconds; the first
build downloads and compiles every dependency, so expect minutes for a big tree, and pick
`medium` if the compiler runs out of memory.
* **Listen on `[::]:$PORT`** (8080 by default): it takes IPv6 and IPv4.
* **Publish it as you run it** with `expose: "private"` (or `"public"` for anyone): it returns `URL`.
* **Step by step**: [Run your own app](https://briq.cloud/docs/guides/run-your-own-app), with a database and a URL.
---
# PHP app recipe
URL: https://briq.cloud/cookbook/php
> Your PHP code served by PHP's built-in server, from files or a GitHub repo. No image to build.
Tags: app, language
Guides:
- [Run your own app](https://briq.cloud/docs/guides/run-your-own-app.md): Your code as a running service, with a URL, in one call and no image to build.
- [Run a GitHub repo](https://briq.cloud/docs/guides/run-a-github-repo.md): An app from a repo, running with a URL. The briq downloads the code itself, and nothing is built on your side.
## Run it
MCP:
```ts
briq_run({
recipe: "php",
params: {
"version": "8.4",
"port": 8080,
"env": {},
"size": "small"
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "php",
"params": {
"version": "8.4",
"port": 8080,
"env": {},
"size": "small"
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "APP_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `version` | enum | 8.4, 8.3 | "8.4" | — |
| `files` | record | { "path": "content" \| { base64 } } | — | Your app's files, path → content (text, or { base64 }). Relative paths go under /app. For a bigger app, or one already on GitHub, pass `repo` instead. Without either, a hello-world app. |
| `repo` | object | { url, ref?, dir?, token? } | — | Your code from a repo instead of `files`. url: "github.com/owner/app", or on another host (GitLab, Bitbucket, Codeberg) the https URL of a .tar.gz archive, without ref. ref: a branch, tag or commit sha; default branch; a full sha pins the code. dir: the app's folder, e.g. "backend". token, private repos only: { secret: "GITHUB_TOKEN", value }, a fine-grained token with Contents: read on this repo; never the person's own token. The briq downloads the code itself, installs when a lockfile changed, runs `build` when the commit changed, then `start` |
| `install` | string | — | — | Shell command replacing the default install step: run before each start; with `repo`, only when a lockfile changed (go and rust build here, at each start) |
| `build` | string | — | — | Shell command run after the install, e.g. "npm run build": with `repo`, only when the commit or the install changed; with files, at each start |
| `start` | string | — | — | Shell command that starts the app (it must not exit). With `repo`, pass it: the default (python app.py, ruby app.rb…) rarely matches a repo; node runs npm start, bun bun run start |
| `port` | number | — | 8080 | — |
| `env` | record | { NAME: "value" \| { secret, value? } } | {} | Env vars. A credential goes as { secret: "NAME", value: "…" }: stored encrypted and never shown again |
| `size` | enum | nano, small, medium, large | "small" | A build (Next.js, Nuxt, a Rust release, a Go toolchain) is many times faster on medium or large: small has one shared CPU, slowed down once a long build used its burst. Up to small, a sleeping briq wakes from a memory snapshot in seconds; medium and large start from scratch on a wake (with `repo`: the branch is looked up again, and a new commit is installed and built before the app answers) |
| `diskGb` | number | — | — | With `repo` only: the size in GB of the volume (/work) that holds the code, its dependencies and build caches |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `APP_URL` | `http://app..internal:8080` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| app | `php:8.4-cli` | 8080 | small | — |
## When to use it
* A handful of PHP pages or a small API, served without Apache, nginx or an image to build.
## Tips
* **Code in a repo**: pass `repo: { url: "github.com/owner/app" }` instead of `files`. See
[Run a GitHub repo](https://briq.cloud/docs/guides/run-a-github-repo).
* **Pass the code as `files`**: `{ "index.php": "…" }`. Relative paths go under `/app`, the
document root, written before the server starts and again whenever it starts over.
* **Served by PHP's built-in server** on `$PORT` (8080 by default), IPv6 and IPv4.
* **No Composer in the image**: include `vendor/` in `files`, or install Composer with `install`.
* **Publish it as you run it** with `expose: "private"` (or `"public"` for anyone): it returns `URL`.
* **Step by step**: [Run your own app](https://briq.cloud/docs/guides/run-your-own-app), with a database and a URL.
---
# Static site recipe
URL: https://briq.cloud/cookbook/static
> HTML, CSS, JavaScript and images served by nginx, from files or a folder of a GitHub repo. No build, no image.
Tags: app, language
Guides:
- [Run your own app](https://briq.cloud/docs/guides/run-your-own-app.md): Your code as a running service, with a URL, in one call and no image to build.
- [Run a GitHub repo](https://briq.cloud/docs/guides/run-a-github-repo.md): An app from a repo, running with a URL. The briq downloads the code itself, and nothing is built on your side.
## Run it
MCP:
```ts
briq_run({
recipe: "static",
params: {
"size": "nano"
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "static",
"params": {
"size": "nano"
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "SITE_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `files` | record | { "path": "content" \| { base64 } } | — | The site's files, path → content (text, or { base64 } for images). Relative paths go under /usr/share/nginx/html; index.html is the home page. |
| `repo` | object | { url, ref?, token?, dir? } | — | The site from GitHub instead of `files`: { url: "github.com/owner/site", ref?, dir?, token? }, as for the language recipes. The briq downloads it at each start (a new commit is picked up then) and serves `dir` (e.g. "public") as it is. A site that needs a build runs on the node recipe instead |
| `size` | enum | nano, small | "nano" | — |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `SITE_URL` | `http://site..internal` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| site | `nginx:1-alpine` | 80 | nano | — |
## When to use it
* A page, a report or a small site the agent generated, and a URL to send someone.
* A built frontend (the output of `vite build`) that needs no server of its own.
## Tips
* **A site on GitHub**: `repo: { url: "github.com/owner/site", dir: "public" }` serves that folder
as it is, downloaded by the briq itself: [Run a GitHub repo](https://briq.cloud/docs/guides/run-a-github-repo).
A site with a build step runs on the [node](https://briq.cloud/cookbook/node) recipe.
* **Pass the site as `files`**: `{ "index.html": "…", "app.js": "…" }`, images as
`{ "base64": "…" }`. Relative paths go under nginx's root; `index.html` is the home page.
* **256 KB in all**: for a bigger site, write the files with `briq_files_put` once it runs, or
fetch them from inside with `briq_exec` (`wget`).
* **Publish it as you run it**:
`briq_run({ recipe: "static", params: { files }, expose: "private" })` returns a `URL` only the
people you send it to can open.
* **Step by step**: [Run your own app](https://briq.cloud/docs/guides/run-your-own-app), with a database and a URL.
---
# Nginx gateway recipe
URL: https://briq.cloud/cookbook/nginx
> A gateway (reverse proxy): one URL for several briqs of a stack, routed by path (/api/ to the back end, / to the front end). One origin for the browser, nothing to change in the apps.
Tags: app, proxy
Guide:
- [Run a GitHub repo](https://briq.cloud/docs/guides/run-a-github-repo.md): An app from a repo, running with a URL. The briq downloads the code itself, and nothing is built on your side.
## Run it
MCP:
```ts
briq_run({
recipe: "nginx",
params: {
"routes": {
"/": "app:8080"
},
"size": "nano"
},
wait: true
})
```
REST:
```bash
curl -X POST https://api.briq.cloud/v1/briqs \
-H "Authorization: Bearer $BRIQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"recipe": "nginx",
"params": {
"routes": {
"/": "app:8080"
},
"size": "nano"
},
"wait": true
}'
# → { "briqs": [{ "id": "bq_…", … }], "outputs": { "GATEWAY_URL": "…" }, … }
# ... when done, for each briq id
curl -X DELETE https://api.briq.cloud/v1/briqs/ \
-H "Authorization: Bearer $BRIQ_API_KEY"
```
## Parameters
| Name | Type | Options | Default | What it does |
| --- | --- | --- | --- | --- |
| `routes` | record | { "/prefix/": "briq:port" } | {"/":"app:8080"} | Path prefix → "briq:port" in the same stack, e.g. { "/api/": "backend:8080", "/": "frontend:8080" }. The longest prefix wins and matches the start of a path (/docs also takes /docs-old; end it with / for a folder); the path is passed on whole (/api/users stays /api/users). Run it after those briqs exist |
| `size` | enum | nano, small | "nano" | — |
## Outputs
Returned by `briq_run` once the stack is healthy. Hosts resolve inside your team network; secrets are generated per run.
| Output | Value |
| --- | --- |
| `GATEWAY_URL` | `http://gateway..internal` |
## What it runs
| Briq | Image | Ports | Size | Volume |
| --- | --- | --- | --- | --- |
| gateway | `nginx:1-alpine` | 80 | nano | — |
## When to use it
* An app in several briqs (front end, back end, database), opened at one URL.
* A front end that calls its API at `/api/…`: one origin, so no CORS and no API address to build in.
## Tips
* **Run it last**: it reads the addresses of the briqs it routes to, and waits for them to run.
* **Routes are path prefixes**: `{ "/api/": "backend:8000", "/": "frontend:8080" }`. The longest
wins, and the path is passed on whole.
* **End a prefix with `/`** to match a folder only: `/docs` also takes `/docs-old`.
* **Name the briqs behind it**: run them with `name: "backend"` and `name: "frontend"`.
* **Expose only the gateway**: the briqs behind it stay private. Its URL is `gateway-…`.
* **Listen on `::`** behind it: it reaches them over the private network, which is IPv6.
* **A 502 for a few seconds** means a briq behind it is still starting, after a wake for example.
* **Host, `X-Forwarded-Host` and WebSockets** go through.
* **Step by step**: [Run a GitHub repo](https://briq.cloud/docs/guides/run-a-github-repo#several-services).