Skip to content
Agentmart
Submit a tool

building-workflows

Build and modify Tines 3B workflows from a workflow or space Git checkout, the 3B MCP server, the 3B CLI, or the in-product editor.

Skill by tines

IndexedApache-2.0★ 1
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/tines-building-workflows

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Build and modify Tines 3B workflows from a workflow or space Git checkout, the 3B MCP server, the 3B CLI, or the in-product editor. Use whenever an agent works with workflow.toml, step directories, config.toml, FROM 3b/base Dockerfiles, workflow routes, links, triggers, connectors, step tests, or needs to create, inspect, run, debug, commit, or publish a 3B workflow.

Use cases: backend, productivity, agent-building

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found
Runs as
Python package

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/building-workflows

What's inside

Skill name
building-workflows
Description
Build and modify Tines 3B workflows from a workflow or space Git checkout, the 3B MCP server, the 3B CLI, or the in-product editor. Use whenever an agent works with workflow.toml, step directories, config.toml, FROM 3b/base Dockerfiles, workflow routes, links, triggers, connectors, step tests, or needs to create, inspect, run, debug, commit, or publish a 3B workflow.
License
Apache-2.0
Compatibility
Tines 3B
Instructions
182 lines in SKILL.md · view on GitHub

Before installing

  • Ships executable scripts

Files (45)

  • SKILL.md
  • openai.yaml · agents/
  • Dockerfile · assets/image-templates/agent/
  • config.toml · assets/image-templates/agent/
  • Dockerfile · assets/image-templates/python/
  • Dockerfile · assets/image-templates/react/
  • Dockerfile · assets/image-templates/shell/
  • Dockerfile · assets/image-templates/typescript/
  • Dockerfile · assets/templates/agent/
  • agent.ts · assets/templates/agent/
  • config.toml · assets/templates/agent/
  • model.json · assets/templates/agent/
  • package.json · assets/templates/agent/
  • config.ts · assets/templates/agent/runtime/
  • contextLimit.ts · assets/templates/agent/runtime/
  • effort.ts · assets/templates/agent/runtime/
  • events.ts · assets/templates/agent/runtime/
  • loop.ts · assets/templates/agent/runtime/
  • model.ts · assets/templates/agent/runtime/
  • request.ts · assets/templates/agent/runtime/
  • response.ts · assets/templates/agent/runtime/
  • selfLoop.ts · assets/templates/agent/runtime/
  • streamResponse.ts · assets/templates/agent/runtime/
  • tools.ts · assets/templates/agent/runtime/
  • transcript.ts · assets/templates/agent/runtime/
  • system.md · assets/templates/agent/
  • getTime.ts · assets/templates/agent/tools/
  • Dockerfile · assets/templates/python/
  • config.toml · assets/templates/python/
  • script.py · assets/templates/python/
  • App.tsx · assets/templates/react/
  • Dockerfile · assets/templates/react/
  • config.toml · assets/templates/react/
  • globals.css · assets/templates/react/
  • mount.tsx · assets/templates/react/
  • package.json · assets/templates/react/
  • render.ts · assets/templates/react/
  • Dockerfile · assets/templates/shell/
  • config.toml · assets/templates/shell/
  • script.sh · assets/templates/shell/
  • Dockerfile · assets/templates/typescript/
  • config.toml · assets/templates/typescript/
  • script.ts · assets/templates/typescript/
  • interfaces.md · references/
  • testing.md · references/

SKILL.md (first lines)

# Build 3B workflows

Read [references/interfaces.md](references/interfaces.md) when choosing or using an editing interface. Read [references/testing.md](references/testing.md) before running a step or creating, updating, or running step tests.

## Layout

```text
README.md
<Step name>/
  README.md
  config.toml
  Dockerfile
  ...
```

Within a workflow checkout, each top-level directory is a uniquely named step. Keep a `README.md` at the root and in every step. The UI already displays the workflow or step name, so do not repeat it as the opening heading.

The workflow README should explain its business purpose, triggers, flow, boundary inputs and outputs, external services, side effects, useful operational notes, and where to make common changes. A step README should identify its trigger and explain its behavior, non-obvious input and output shapes, external endpoints, and connectors. Link to workflow files with relative Markdown paths, wrapping paths containing spaces in angle brackets. Update a README when behavior or structure changes materially, but not for a behavior-preserving refactor.

A cloned 3B space adds one directory per workflow:

```text
<Workflow name>/
  workflow.toml
  README.md
  <Step name>/
    ...
```

`workflow.toml` identifies an existing workflow. Preserve its `id`, and never copy it into another workflow directory. In a 3B-hosted space clone, pushing a new top-level directory without `workflow.toml` creates that workflow as a draft from a non-`main` branch or in Live from `main`; 3B writes the identity file back.

## Step templates

Templates map to `shell` → `script.sh`, `python` → `script.py`, `typescript` → `script.ts` on Bun, `react` → `App.tsx` with React and Tailwind, and `agent` → `agent.ts`. React templates set `output = true`.

Copy the closest template available through the current interface. Default to TypeScript for data processing when the user has not requested another language. In a Git checkout without interface-provided templates, copy the matching directory from [assets/templates](assets/templates) into the workflow and rename it for the step. A step may contain and import additional source files; the template entry point is the command the runtime invokes. A step builds from its own folder only, so it can’t import files from the workflow root or another step: copy a shared helper into each step that uses it. Add Python dependencies to `requirements.txt` and TypeScript or React dependencies to `package.json`; preserve the template’s install and cache layers instead of adding ad hoc installs to the Dockerfile.

For React, default to one step for one application. Do not place the UI downstream of a data step: render it immediately and fetch data from route steps. For multi-page applications, use `BrowserRouter` with `basename={window.__ROUTE_PATH__}` and relative route paths; the template computes the branch-aware base path. Use Tailwind’s built-in palette and spacing scale, and avoid adding browser dependencies without a concrete need.

Render a descriptive `<title>` for every page. Include an app-specific favicon in every web application, including plain HTML pages. Preserve an existing custom favicon; otherwise, create a simple SVG mark using the application’s colors and identity, legible at 16×16. Put `<link rel="icon" type="image/svg+xml">` in the HTML `<head>` (`render.ts` for React), replacing the template’s title-derived favicon link. Set its `href` to `data:image/svg+xml,` followed by the SVG encoded with `encodeURIComponent`, so the favicon works without a separate asset route. A webpage is complete only when its title and favicon are set.

## `config.toml`

All fields are optional at runtime, and a missing `color` defaults to `sky`. Set a color in authored steps, and omit unused fields rather than writing empty values.

```toml
color = "sky"
output = true
route = "/document-summary"
route_auth = "space"
route_type = "api"
title = "Document summary"
cron = "0 * * * *"
email_address = "support"
timeout = 60
retry_seconds = [1, 2, 3]
links = ["Store result", "Notify"]
connectors = [{ name = "slack", type = "slack" }]
pinned = true
```

- Colors: `pink`, `purple`, `teal`, `green`, `orange`, `red`, or `sky`.
- `output`: makes stdout the HTTP response.
- `route`: assigns an HTTP path. Live routes must be unique among workflows that share an edge host. `/` is that host’s catch-all and should be used only for an explicitly requested homepage.
- `route_auth`: defaults to `space`.
- `route_type`: exposes the route on the Links page as `webpage`, `api`, `webhook`, or `other`.
- `title`: names a route exposed on the Links page; set it whenever `route_type` is present.
- `cron`: schedules the published step; drafts do not run schedules.
- `email_address`: gives the step an inbound email trigger; the raw message becomes stdin.
- `timeout`: accepts 1–300 seconds and defaults to 45.
- `retry_seconds`: accepts at most 10 whole-second delays from 1–1,800. Each value schedules another whole-step attempt after a runtime command exits nonzero, so `[1, 2, 3]` permits four attempts. It does not retry builds, step tests, timeouts, out-of-memory failures, or missing commands. Use it only when replaying side effects is safe.
- `links`: names downstream step directories. Do not list the same target twice.
- `connectors`: is managed by connector tooling, never by hand.
- `pinned`: places a typed route first on the Links page; the UI normally manages it.

## Process and link semantics

Each step is an isolated process. Its raw stdout becomes stdin for every linked downstream step. Fan-out runs in parallel. With multiple upstream steps, the most recent successful upstream output is used.

Triggers compose with links. A step with `route` can also be a downstream target or link to itself. An external invocation supplies a complete HTTP request on stdin, while a linked invocation supplies the upstream step’s raw stdout, so code reached both ways must handle both input shapes.

Zero-byte stdout suppresses downstream execution. A step reports failure only through a nonzero exit status. Do not catch an error, log it, and continue unless success is intentional. 3B retains at most 10 KiB of stderr as its diagnostic output; stdout is the workflow data channel.

A step with no trigger receives empty stdin. A route step receives a complete RFC 7230 HTTP request. An email step receives the raw RFC 822 message.

## HTTP routes

The responding step needs `output = true` and must emit a complete HTTP response with `\r\n` line endings and a `\r\n\r\n` separator before the body. Without a reachable output step, 3B returns `202 Accepted` with no body.

| `route_auth`  | Access                                                    |
| ------------- | --------------------------------------------------------- |
| `space`       | Members of the workflow’s space; the default              |
| `tenant`      | Any authenticated tenant member                           |
| `sso`         | External users authenticated by the tenant’s SSO provider |
| `external_id` | Anyone holding the route’s unguessable ID                 |
| `connector`   | Workflows using a workflow-backed connector               |
| `public`      | Unauthenticated internet access                           |

For a webhook or callback, write `route_auth = "external_id"` without an `:id` suffix; 3B mints and persists the ID. Call the route with that value in the `external_id` query parameter. Never invent it. Use `public` only when explicitly requested. Draft routes configured as `public`, `external_id`, `sso`, `tenant`, or `connector` are still floored to space-private access until published. Draft previews require space access and do not enforce the SSO `route_sso_groups` restriction.

Every routed workflow needs at least one `route_type`. Give each typed route a `title`, type every externally callable API endpoint as `api`, and leave internal callbacks and helpers untyped.

An API route intended for callers should include `api.json`: a nonempty object keyed by lowercase HTTP method whose values are OpenAPI 3.1 Operation Objects. 3B derives the path and security, so omit `paths`, `servers`, and `security`. Inline schemas instead of using component references. An `api.json` file is rejected unless its step has a non-root route with `route_type = "api"`.

`space` and `tenant` routes accept a browser session, a 3B API key, or a 3B OAuth access token. `sso` authenticates external users through the tenant’s configured SAML or OIDC provider without creating a 3B account. When the tenant has more than one SSO provider, add `route_idp = "<provider ID>"` next to `route_auth = "sso"` to designate which provider gates the route; without it, the tenant’s primary provider is used. Only set `route_idp` to one of the tenant’s registered provider IDs — never invent one. Successful `space`, `tenant`, and `sso` authentication adds a spoof-proof `x-3b-authenticated-email` header. 3B strips its bearer token before invoking step code. A `connector` route is called only through a workflow-backed connector; the proxy supplies its authentication header. When a user triggered the calling workflow’s run (through a `space`, `tenant`, or `sso` route, or chat), the connector route also receives that user’s `x-3b-authenticated-email` and `x-3b-authenticated-groups` (current 3B groups for members, or the verified IdP group snapshot for external SSO callers); calls from schedules, webhooks, or service accounts carry neither. Every call from a running workflow, including scheduled and webhook runs, also receives spoof-proof `x-3b-calling-workflow-id`, `x-3b-calling-space-id`, and `x-3b-calling-branch` headers; the branch is `main` for the live version, otherwise the draft branch’s ID. The identity headers name the user who started the calling run, not whoever wrote the calling workflow’s code, so a route that authorizes on them should also check that the calling workflow is one it trusts and that the branch is `main`.

Step code can read verified group names from the spoof-proof `x-3b-authenticated-groups` header, a JSON array of strings. Parse it as JSON, never split on commas. It contains the IdP group snapshot for SSO callers and current 3B group names for members; it is absent when there are no verified groups. 3B strips caller-supplied values on every route before injecting verified names.

To restrict an `sso` route to certain IdP groups, add `route_sso_groups = ["Security Team"]`: 3B answers 403 before the step runs unless the caller belongs to at least one listed group, compared case-insensitively. The provider must emit the `groups` claim. Use values the user confirms are emitted — never invent them. `route_sso_groups` requires `route_auth = "sso"`; other auth modes are rejected during facet synchronization, including for drafts.

External group membership is a snapshot: browser SSO sessions retain it for two hours, and OAuth retains it through a fixed 30-day refresh chain, with up to 30 additional minutes for the final access token. Refreshing does not update groups, so IdP group removal does not promptly revoke access. Workflow runs and chained workflow connectors retain the snapshot captured at entry for the lifetime of those runs, including after the original sign-in expires. Missing groups, including claims dropped because their base64url JSON exceeds 2 KB, cannot satisfy `route_sso_groups`.

A route accepting OAuth clients should render its own consent screen: when a client signs in, 3B serves the route with unspoofable `x-3b-consent-*` headers (a signed challenge, a decision URL, display values, and the caller’s connector grants when the route uses visitor-mode connectors), and the step returns an HTML Allow/Deny page that posts the decision back (the mcp-builder skill documents the contract). No config key or extra route is needed; a step that ignores the headers gets a neutral built-in screen.

When adding or changing a route, tell the user who can access it. Do not describe a route as public when draft access is still floored to space membership.

Cookies are pinned to the serving host. 3B strips `Domain`, changes `SameSite=None` to `SameSite=Lax`, signs `HttpOnly` values for the space, and forces `Secure` on HTTPS responses. Prefer `__Host-` cookie names with `Path=/`, `Secure`, and `HttpOnly`; omit `HttpOnly` only when browser JavaScript must read the cookie.

Keep APIs synchronous only for short, bounded work. For long or variable work, promptly return `202 Accepted` with a durable operation ID and status URL, then continue downstream. Because that HTTP response becomes downstream stdin, include the operation ID and required job payload in its body and parse the HTTP message in the next step. Persist pending, succeeded, and failed state in a named volume, and make retries idempotent. An empty automatic `202` is only for fire-and-forget work; use `201 Created` only when the requested resource has been created before responding.

From tines/skills, Apache-2.0.

More from tines/skills

Signals

Stars
1
Forks
2
Open issues
0
Last commit (this folder)
Oct 23, 2026 (5 days ago)
Last release
Oct 23, 2026 (5 days ago)

From GitHub (fetched Oct 24, 2026).

Details

License
Apache-2.0
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from tines

Cite this page

building-workflows skill. Agent Mart. https://agentmart.dev/skills/tines-building-workflows (last updated 2026-10-24)