Note
v0.3.0 - Tempo is in ALPHA - API surface and data structures subject to change
Tempo is a workflow automation platform for building, running, and monitoring tenant-scoped data flows. A flow is made of reusable steps, invoked through triggers, persisted with artifacts, and observed through run history, request history, OpenAPI, and MCP.
Tempo ships as:
Tempo: the core workflow/orchestration libraryTempo.Core: server-facing persistence, runtime, settings, and management contractsTempo.Server: the REST API hostTempo.Worker: the first-party distributed execution worker daemonTempo.McpServer: an MCP facade over Tempo.Server built on Voltaicdashboard/: a React/Vite operator UIsdk/csharp,sdk/js, andsdk/python: artifact runtime SDKs with exhaustive test apps
- Tenant-scoped CRUD for data flows, steps, triggers, runs, artifacts, users, credentials, roles, and permissions
- Flow-level invocation auth modes so HTTP-triggered data flows can be public bearer-capability endpoints or require normal Tempo API authentication (
PublicvsApiAuthenticated) - Runtime model that supports
Builtin.Class,Builtin.Method,External.Rest,Artifact.Process,Artifact.Python,Artifact.JavaScript,Artifact.DotnetProcess, andHost.Executable - Source-step creation from the UI or API for Python, JavaScript, and C#
- Mutable artifact packages with dashboard file browsing and in-place editing
- Runtime-aware startup seeding that creates working sample steps for each available runtime type
- Distributed execution with a control-plane/server split, authenticated workers, worker drain/resume/block control, and capability-aware run placement
- Run placement metadata, worker management REST routes, dashboard worker views, and MCP worker tools
- Durable per-run log capture with tenant-scoped run activity and run-log APIs plus dashboard run-log viewing
- Admin log viewer for file-backed server and worker logs in the dashboard, REST API, MCP, and Postman
- OpenAPI-backed API Explorer and MCP server for agent-driven automation
- First-run setup wizard that creates and invokes example flows end to end
- Dashboard internationalization across login, shell navigation, workspace headers, tables, filters, modals, and hover/help text, with locale selection, locale-aware formatting, generated locale resources, and audit enforcement for supported ship locales
- K-sortable PrettyId identifiers with fixed prefixes and a maximum length of 32
- Docker Compose deployment, image build scripts, and NuGet publish script
From the repository root:
docker compose -f .\docker\compose.yaml up -dDefault endpoints:
- Dashboard:
http://localhost:3000 - Tempo.Server:
http://localhost:8901 - Tempo.Worker: included in the compose stack as
tempo-worker-1,tempo-worker-2, andtempo-worker-3 - Tempo.McpServer HTTP RPC:
http://127.0.0.1:8910/rpc - Tempo.McpServer TCP:
127.0.0.1:8911 - Tempo.McpServer WebSocket:
ws://127.0.0.1:8912/mcp
Default seeded credentials on an empty database:
- Email:
admin@tempo.local - Password:
password - Local admin API key:
tempo-local-admin-api-key
Compose bind-mounts docker/tempo.server.json and docker/tempo.worker.json so first-run deployments use the intended control-plane and worker settings without depending on pre-seeded config volumes. Persistent named volumes remain in place for the server database, server artifact blob storage, server logs/runtime cache/scratch, shared worker logs, shared run logs, dashboard logs, and MCP configuration. Worker runtime-cache and scratch paths remain container-local anonymous volumes so scaled workers do not share mutable runtime state, while worker log files are written to a shared named volume that Tempo.Server mounts read-only for the admin log viewer. Per-run logs are written to a separate shared volume mounted read-write by the server and workers so run logs survive container restarts and remain visible through the Runs view and tenant-scoped run-log APIs. The service images in the compose file are pinned to v0.3.0.
Tempo v0.3.0 splits the platform into:
Tempo.Serveras the control plane for REST, MCP, scheduling, persistence, worker management, and authenticated artifact downloadTempo.Workeras the execution plane for assigned flow runs
The server can still participate in execution through the local pseudo-worker controlled by engine.serverCanExecuteWorkload. Placement is whole-flow-run based, with LeastLoaded and LabelPinned strategies.
Recommended prerequisites:
| Tool | Required for |
|---|---|
| .NET 10 SDK | Tempo, Tempo.Core, Tempo.Server, Tempo.McpServer, tests |
| Node.js | Dashboard development and Artifact.JavaScript runtime |
| Python 3 | Artifact.Python runtime |
dotnet command |
Artifact.DotnetProcess runtime and C# source-step packaging |
Tempo.Server does not fail startup when optional runtime commands are unavailable. Instead, those runtimes are surfaced as unavailable in the runtime catalog and their startup template steps are skipped. Configure command names or absolute paths in tempo.json under runtimes.externalExecution.
Build and run:
dotnet build .\src\Tempo.sln
dotnet run --project .\src\Tempo.Server\Tempo.Server.csproj
dotnet run --project .\src\Tempo.Worker\Tempo.Worker.csproj
dotnet run --project .\src\Tempo.McpServer\Tempo.McpServer.csproj
cd .\dashboard
npm install
npm run devHelper scripts at the repository root:
build-server.bat v0.3.0build-worker.bat v0.3.0build-mcp.bat v0.3.0build-dashboard.bat v0.3.0publish-nuget.bat <nuget-api-key>
| Concept | Purpose |
|---|---|
| Step | A reusable execution unit bound to a runtime and an execution key |
| Data flow | A directed workflow that chains steps through success, failure, and exception edges |
| Trigger | A reusable entry point that invokes a data flow |
| Artifact | A mutable package of files used by artifact-backed runtimes |
| Run | One execution of a data flow |
| Request history | Captured inbound HTTP traffic, response bodies, headers, and summary buckets |
Flows reference steps by executionKey, not by step record ID. This keeps flow definitions stable even when the step row is edited or replaced.
Each flow also controls how its HTTP trigger is invoked through invocationAuthMode:
Public- anyone with the trigger URL can invoke the flowApiAuthenticated- the caller must present normal Tempo API credentials and be allowed to act on the flow's tenant
The dashboard surfaces this in the Data Flows workspace as explicit public versus API-authenticated trigger choices.
The dashboard now ships with operator-facing internationalization wired through the core UI surface:
- language selection before authentication on the login page and after authentication in the topbar
- persisted locale preference via
tempo.locale - locale-aware formatting for dates, times, numbers, durations, byte sizes, booleans, and lists
- localized workspace titles and subtitles, table headers, buttons, modal labels, filters, tooltips, status/enum chips, and shared navigation chrome
- generated locale resources plus an audit test that fails CI if new raw localizable UI text or unsupported English fallback is introduced
Supported ship locales in the dashboard selector are:
eneszh-Hansyue-Hant-HKjadefritzh-Hant-TW
If product or operators refer to "Kanji" as a selector label, the locale registry treats it as an alias for ja rather than a separate language.
Tempo supports two HTTP-trigger invocation modes at the data-flow level:
invocationAuthMode |
Behavior | Typical use |
|---|---|---|
Public |
Anyone with the trigger URL can invoke the flow | Webhooks, low-friction inbound automation, capability-URL patterns |
ApiAuthenticated |
Caller must supply standard Tempo API credentials and have access to the flow tenant | Internal automations, tenant-private flows, operator-driven integrations |
The generated curl guidance in the dashboard follows the selected mode. Public flows generate a bare trigger call, while API-authenticated flows add an Authorization: Bearer ... header placeholder.
This distinction is carried through the dashboard UX: the Data Flows workspace exposes the run policy explicitly, the API Explorer and trigger guidance reflect the expected auth shape, and route-level docs call out whether a trigger should be treated as a capability URL or a tenant-authenticated endpoint.
| Runtime key | Purpose |
|---|---|
Builtin.Class |
Executes a registered Tempo.Step subclass |
Builtin.Method |
Executes a registered [StepMethod] method |
External.Rest |
Executes a persisted outbound HTTP request |
Artifact.Process |
Executes a package-local process that speaks Tempo protocol v1 |
Artifact.Python |
Executes a Python handler from an artifact package |
Artifact.JavaScript |
Executes a Node.js handler from an artifact package |
Artifact.DotnetProcess |
Executes a .NET handler from an artifact package using the Tempo SDK host and TempoStepHandlerBase helpers |
Host.Executable |
Executes an operator allowlisted host executable |
Legacy.InlineRest remains a compatibility read path. New REST steps should use External.Rest.
On an empty database, Tempo seeds:
- A default tenant, administrator, tenant user, and credential
- Four protected tenant roles:
Administrator,Editor,Operator, andReadOnly - Built-in runtime sample steps
- Artifact-backed sample steps and sample artifacts for every available artifact runtime
- A host executable sample only when a host allowlist entry is enabled
The dashboard opens a setup wizard on first access. The wizard explains what Tempo is about to create, then creates:
- An echo step packaged from source
- An echo flow and POST trigger
- A chained flow that generates a random number and doubles it
- A GET trigger for the chained flow
- Sample invocations that show both response bodies and response headers
Every workspace in the dashboard includes a page title and subtitle, and sidebar scrolling is independent from workspace scrolling.
HTTP trigger routes are:
/v1.0/triggers/http/{triggerId}
Flows default to public trigger invocation, where the trigger ID acts as a bearer capability. Set the flow field invocationAuthMode to ApiAuthenticated when trigger calls should require normal Tempo API credentials and tenant access.
For successful trigger execution:
- The HTTP response body is the final step output body
- Execution metadata is returned in headers, not mixed into the JSON body
Current response metadata headers include:
x-tenant-idx-worker-idwhen the run has been assignedx-run-idx-dataflow-idx-trigger-idx-run-statex-run-created-utcx-run-started-utcx-run-completed-utcx-run-last-update-utcx-runtime-msx-run-errorwhen applicable
Tempo includes SDKs for artifact-backed handlers:
Notes:
- The C# SDK targets
net8.0andnet10.0 - The server-side projects target
net10.0 - Each SDK ships with a test application intended to exercise the public API surface exhaustively
- The SDKs expose ambient execution context and file-backed step logging so handler code can write diagnostics without corrupting protocol stdout
Artifacts are file packages, not opaque zip-only deployment units. Tempo stores package contents in a way that supports:
- Uploading artifacts and versions
- Editing individual files in the dashboard
- Creating steps directly from pasted Python, JavaScript, or C# source
- Reusing one artifact across multiple steps and versions
For artifact-backed runtimes and manifests, see docs/ARTIFACT_MANIFEST.md.
Primary reference material:
- docs/REST_API.md
- docs/MCP_API.md
- docs/BEST_PRACTICES.md
- docs/DISTRIBUTED_EXECUTION_OPERATOR_GUIDE.md
- docs/WORKER_PROTOCOL.md
- Tempo.postman_collection.json
Additional operator and implementation guides:
- docs/RUNTIME_PROVIDER_AUTHORING.md
- docs/ARTIFACT_MANIFEST.md
- docs/PROTOCOL_V1.md
- docs/PYTHON_ARTIFACT_QUICKSTART.md
- docs/EXTERNAL_EXECUTION_OPERATOR_GUIDE.md
- docs/SECURITY_TRUST_BOUNDARIES.md
- docs/INLINE_REST_MIGRATION.md
- docs/DASHBOARD_ARTIFACTS_RUNTIMES.md
Archived planning docs:
OpenAPI is exposed at:
http://localhost:8901/openapi.json
Runtime configuration schemas in OpenAPI use oneOf, which keeps the API Explorer and generated clients aligned with the concrete runtime config being used.
Core solution:
dotnet build .\src\Tempo.sln
dotnet run --project .\src\Test.Automated\Test.Automated.csproj
dotnet test .\src\Test.Xunit\Test.Xunit.csproj
dotnet test .\src\Test.Nunit\Test.Nunit.csproj
npm.cmd --prefix .\dashboard run buildSDK test applications:
dotnet run --project .\sdk\csharp\Tempo.Sdk.TestApp\Tempo.Sdk.TestApp.csproj
npm.cmd --prefix .\sdk\js test
python .\sdk\python\test_app\test_sdk.pyNuGet packaging:
publish-nuget.bat YOUR_NUGET_API_KEYThat script packs and pushes:
TempoTempo.Sdk- their matching
.snupkgsymbol packages
| Path | Purpose |
|---|---|
src/Tempo |
Core orchestration library |
src/Tempo.Core |
Persistence, runtimes, settings, server contracts |
src/Tempo.Server |
REST API host |
src/Tempo.Worker |
Worker daemon for distributed execution |
src/Tempo.McpServer |
MCP bridge over Tempo.Server |
dashboard |
React/Vite operator UI |
sdk/csharp |
C# SDK and test app |
sdk/js |
JavaScript SDK and test app |
sdk/python |
Python SDK and test app |
docker |
Compose file and container config |
docs |
Focused operator and developer guides |
archive |
Superseded planning notes and archived implementation docs |
| Technology | Role in Tempo |
|---|---|
| .NET 10 | Primary runtime for Tempo, Tempo.Core, Tempo.Server, Tempo.McpServer, and the server-side test projects |
| Watson | Embedded web server used by Tempo.Server for HTTP routing, OpenAPI exposure, and trigger/API handling |
| Voltaic | MCP scaffolding and transport layer used by Tempo.McpServer |
| React 19 | Component model for the dashboard UI |
| React Router 7 | Client-side routing for dashboard workspaces and navigation |
| Vite 6 | Dashboard development server and production build toolchain |
| i18next and react-i18next | Dashboard internationalization, locale detection, translation lookup, and locale-aware UI wiring |
| Microsoft.Data.Sqlite | SQLite persistence provider for local and lightweight Tempo deployments |
| Microsoft.Data.SqlClient | SQL Server persistence provider |
| Npgsql | PostgreSQL persistence provider |
| MySqlConnector | MySQL persistence provider |
| PrettyId | K-sortable ID generation for Tempo resource identifiers |
| RestWrapper | Outbound HTTP execution support for REST-backed steps |
| SyslogLogging | Structured logging used across the server-side projects |
Follow the coding and review rules in CLAUDE.md. Keep README, changelog, API docs, and the Postman collection in sync with code changes.
MIT. See LICENSE.md.
Logo provided by softicons.com.
