concept ~9 min
TraceServer - Remote Trace Dashboard

- [Overview](#overview)

TraceServer - Remote Trace Dashboard

Table of Contents

Overview

TPipe-TraceServer is a standalone module that provides a real-time web dashboard for viewing trace reports dispatched from running TPipe agents. It receives trace data over HTTP, stores it in memory, and broadcasts updates to connected dashboard clients over WebSocket.

This is useful when you have one or more TPipe agents running in production or development and want a centralized place to inspect their execution traces without embedding trace output into each agent’s own logs.

Key capabilities:

  • REST API for submitting and retrieving trace reports
  • WebSocket endpoint for live trace streaming to connected browsers
  • Dual authentication: separate auth flows for agents (submitting traces) and human clients (viewing the dashboard)
  • Built-in HTML dashboard with search and filtering
  • Configurable port and host binding

Architecture

┌──────────────┐     POST /api/traces     ┌──────────────────────┐
│  TPipe Agent  │ ──────────────────────► │                      │
│  (Pipe/       │   (Agent Auth)          │    TraceServer       │
│   Pipeline)   │                         │                      │
└──────────────┘                          │  ┌────────────────┐  │
                                          │  │ TraceServer     │  │
┌──────────────┐     POST /api/traces     │  │ Registry        │  │
│  TPipe Agent  │ ──────────────────────► │  │  - traces       │  │
│  (Manifold)   │   (Agent Auth)          │  │  - sessions     │  │
└──────────────┘                          │  │  - connections  │  │
                                          │  └────────────────┘  │
                                          │                      │
┌──────────────┐   GET /api/traces        │                      │
│  Browser      │ ◄─────────────────────  │                      │
│  Dashboard    │   WS /ws/traces         │                      │
│               │ ◄─────────────────────  │                      │
└──────────────┘   (Client Auth)          └──────────────────────┘

Agents authenticate with a bearer token when submitting traces. Dashboard users authenticate through a separate login flow and receive a session token for subsequent requests and WebSocket connections.

Getting Started

Dependency

Add the TraceServer module to your project:

dependencies {
    implementation("com.TTT:TPipe-TraceServer:1.0.0")
}

Minimal Startup

import com.TTT.TraceServer.startTraceServer

fun main()
{
    // Start on default port 8081, non-blocking
    startTraceServer()
    
    // Your application continues running...
}

Open http://localhost:8081 in a browser to see the dashboard.

Configuration

TraceServerConfig

TraceServerConfig controls the server’s network binding:

import com.TTT.TraceServer.TraceServerConfig

// Change port (default: 8081)
TraceServerConfig.port = 9090

// Change host binding (default: "0.0.0.0")
TraceServerConfig.host = "127.0.0.1"

// Then start the server
startTraceServer()
PropertyTypeDefaultDescription
portInt8081Port the server listens on
hostString"0.0.0.0"Host address to bind to

You can also pass port and host directly to startTraceServer():

startTraceServer(port = 9090, host = "127.0.0.1", wait = true)

The wait parameter controls whether the call blocks the current thread. Set wait = true when TraceServer is your main application entry point, or false (default) when embedding it alongside other services.

Dual Authentication Model

TraceServer uses two independent authentication mechanisms — one for agents submitting traces and one for human clients viewing the dashboard. Both are optional and disabled by default.

Agent Authentication

Agent auth validates the Authorization header on POST /api/traces. This is the path used by RemoteTraceDispatcher when agents push trace data to the server.

import com.TTT.TraceServer.TraceServerRegistry

// Validate agent bearer tokens
TraceServerRegistry.agentAuthMechanism = { authHeader ->
    authHeader == "Bearer my-agent-secret"
}

When no agentAuthMechanism is set, TraceServer falls back to P2PRegistry.globalAuthMechanism if one is configured. If neither is set, agent submissions are accepted without authentication.

Client Authentication

Client auth protects the dashboard endpoints (GET /api/traces, GET /api/traces/{id}, WS /ws/traces). Clients authenticate via POST /api/auth/login and receive a session token valid for 24 hours.

import com.TTT.TraceServer.TraceServerRegistry

// Validate dashboard login credentials
TraceServerRegistry.clientAuthMechanism = { key ->
    key == "my-dashboard-password"
}

When clientAuthMechanism is null, all dashboard endpoints are open without authentication.

Auth Flow Summary

EndpointAuth TypeHeader/Param
POST /api/tracesAgent authAuthorization: Bearer <token>
POST /api/auth/loginClient loginJSON body {"key": "..."}
GET /api/tracesClient sessionAuthorization: Bearer <session>
GET /api/traces/{id}Client sessionAuthorization: Bearer <session>
WS /ws/tracesClient sessionQuery param ?token=<session>

REST API Endpoints

POST /api/auth/login

Authenticates a dashboard client and returns a session token.

Request:

{"key": "my-dashboard-password"}

Response (200):

{"token": "uuid-session-token"}

Response (401): "Invalid credentials"

When no clientAuthMechanism is configured, returns an anonymous session token without validation.


POST /api/traces

Submits a trace report from an agent. Requires agent authentication if configured.

Request:

{
    "pipelineId": "pipeline-abc-123",
    "htmlContent": "<html>...trace report...</html>",
    "name": "My Pipeline Run",
    "status": "SUCCESS"
}

Response: 200 OK

After storing the trace, the server broadcasts a summary to all connected WebSocket clients so the dashboard updates in real time.


GET /api/traces

Returns a list of all stored trace summaries, sorted by most recent first. Requires client session if clientAuthMechanism is configured.

Response:

[
    {
        "id": "pipeline-abc-123",
        "timestamp": 1710600000000,
        "name": "My Pipeline Run",
        "status": "SUCCESS"
    }
]

GET /api/traces/{id}

Returns the full trace payload for a specific pipeline ID, including the HTML report content.

Response:

{
    "pipelineId": "pipeline-abc-123",
    "htmlContent": "<html>...full trace report...</html>",
    "name": "My Pipeline Run",
    "status": "SUCCESS"
}

Response (404): "Trace not found"

WebSocket Live Streaming

WS /ws/traces

Connect to receive real-time trace summary broadcasts as agents submit new traces.

Connection: ws://localhost:8081/ws/traces?token=<session-token>

The token query parameter is required when clientAuthMechanism is configured. Each time an agent submits a trace via POST /api/traces, all connected WebSocket clients receive a JSON summary:

{
    "id": "pipeline-abc-123",
    "timestamp": 1710600000000,
    "name": "My Pipeline Run",
    "status": "SUCCESS"
}

The server sends periodic WebSocket pings (every 15 seconds) to keep connections alive.

Connecting Agents with RemoteTraceDispatcher

The easiest way to send traces to a TraceServer is through RemoteTraceConfig and RemoteTraceDispatcher. These live in TPipe’s Debug package in the root project and handle serialization, HTTP transport, and authentication automatically.

Automatic Dispatch

Configure RemoteTraceConfig so that every call to PipeTracer.exportTrace() automatically pushes the trace to your server:

import com.TTT.Debug.RemoteTraceConfig

RemoteTraceConfig.remoteServerUrl = "http://localhost:8081"
RemoteTraceConfig.dispatchAutomatically = true

// Optional: set auth header manually
RemoteTraceConfig.authHeader = "Bearer my-agent-secret"

With dispatchAutomatically = true, any call to PipeTracer.exportTrace(pipelineId, format) will also fire off an async HTTP POST to the TraceServer with the HTML report.

AuthRegistry Integration

If you use AuthRegistry (or TPipeConfig.addRemoteAuth()) to register tokens for your services, RemoteTraceDispatcher will automatically resolve the token for the TraceServer URL when RemoteTraceConfig.authHeader is not explicitly set:

import com.TTT.Config.TPipeConfig

// Register auth for the trace server URL
TPipeConfig.addRemoteAuth("http://localhost:8081", "my-agent-secret")

// RemoteTraceDispatcher will resolve "Bearer my-agent-secret" automatically
RemoteTraceConfig.remoteServerUrl = "http://localhost:8081"
RemoteTraceConfig.dispatchAutomatically = true

Manual Dispatch

You can also dispatch traces manually at any point:

import com.TTT.Debug.RemoteTraceDispatcher

// Dispatch a specific pipeline's trace
RemoteTraceDispatcher.dispatchTrace(
    pipelineId = "my-pipeline-run",
    name = "Research Task",
    status = "SUCCESS"
)

The dispatcher exports the trace as HTML from PipeTracer, wraps it in a TracePayload, and POSTs it to RemoteTraceConfig.remoteServerUrl. The HTTP call runs on Dispatchers.IO and does not block the calling coroutine.

Dashboard

The built-in dashboard is served at the root URL (/) and provides:

  • Trace list view showing all submitted traces with pipeline ID, name, status, and timestamp
  • Search and filtering to find specific traces by name or status
  • Detail view rendering the full HTML trace report inline
  • Live updates via WebSocket — new traces appear automatically without page refresh

The dashboard is a single-page HTML application bundled as static resources inside the TraceServer module.

Standalone Execution

TraceServer can run as a standalone application from the command line:

# Default: port 8081, host 0.0.0.0
java -jar TPipe-TraceServer.jar

# Custom port and host
java -jar TPipe-TraceServer.jar --port 9090 --host 127.0.0.1

Complete Example

This example starts a TraceServer, configures agent auth, runs a pipeline with tracing enabled, and dispatches the trace to the server:

import com.TTT.Debug.RemoteTraceConfig
import com.TTT.Debug.TraceConfig
import com.TTT.Debug.TraceFormat
import com.TTT.Debug.PipeTracer
import com.TTT.TraceServer.TraceServerRegistry
import com.TTT.TraceServer.startTraceServer
import bedrockPipe.BedrockPipe
import com.TTT.Pipeline.Pipeline
import kotlinx.coroutines.runBlocking

fun main() = runBlocking {
    // 1. Configure and start TraceServer
    TraceServerRegistry.agentAuthMechanism = { auth ->
        auth == "Bearer agent-token-123"
    }
    startTraceServer(port = 8081)

    // 2. Configure remote dispatch
    RemoteTraceConfig.remoteServerUrl = "http://localhost:8081"
    RemoteTraceConfig.authHeader = "Bearer agent-token-123"
    RemoteTraceConfig.dispatchAutomatically = true

    // 3. Build a traced pipeline
    val pipeline = Pipeline()
        .enableTracing(TraceConfig(enabled = true))
        .add(BedrockPipe()
            .setPipeName("analyzer")
            .setSystemPrompt("Analyze the input.")
            .setModel("anthropic.claude-3-sonnet-20240229-v1:0")
            .setRegion("us-east-1")
        )

    pipeline.init()
    val result = pipeline.execute("Explain quantum computing")

    // 4. Export trace — automatically dispatched to TraceServer
    PipeTracer.exportTrace(pipeline.pipelineId, TraceFormat.HTML)

    // Dashboard at http://localhost:8081 now shows the trace
    println("Trace dispatched. View at http://localhost:8081")
}

Best Practices

  • Separate agent and client auth — use strong tokens for agent auth and simpler credentials for dashboard login during development
  • Use dispatchAutomatically = true during development so every trace export lands in the dashboard without extra code
  • Use AuthRegistry instead of hardcoding RemoteTraceConfig.authHeader when your agents already register tokens for other remote services
  • Run TraceServer on a separate port from your MemoryServer or other Ktor services to avoid routing conflicts
  • Set wait = false when embedding TraceServer inside a larger application so it doesn’t block your main thread
  • Monitor WebSocket connections — the server cleans up closed connections automatically, but long-running dashboards should handle reconnection on the client side

Related:

Next Steps

  • P2P Overview - Continue into agent-to-agent communication.