Skip to content
Forticia
Research
Quantitative FinanceEquities, FX, futures. Factors and backtests, every run replayable.Computational BiologySequence, folding, simulation. Versioned, reproducible labs.Cultural IntelligencePhilosophy, governance, ethics. How institutions decide and answer for it.AI InstrumentationPrivate models. Multi-agent orchestration. Guardrails on write.View all research
Quantitative Finance
  • Equities, FX, futures
  • Factors and backtests
  • Every run logged and replayable
InfrastructurePapersPolarisLink™About
Sign inRequest access
Request access

Research

Quantitative FinanceEquities, FX, futures. Factors and backtests, every run replayable.Computational BiologySequence, folding, simulation. Versioned, reproducible labs.Cultural IntelligencePhilosophy, governance, ethics. How institutions decide and answer for it.AI InstrumentationPrivate models. Multi-agent orchestration. Guardrails on write.

Platform

InfrastructurePapersPolarisLink™About
Request accessSign in
Forticia

A private institute for computational research. It publishes original research and runs a governed environment where every run is logged and replayable.

Sign inSystem status

Research

Quantitative FinanceComputational BiologyCultural IntelligenceAI Instrumentation

Infrastructure

WorkspacesHelper planeGoverned AIPapersStatus

PolarisLink™

SpecificationQuickstartClientsChangelogGitHub repository

Institute

AboutRequest accessContactSign inForticia on GitHub

Forticia publishes research and simulations. Nothing on this site is investment advice.

© 2026 ForticiaPrivacyTerms
Home/PolarisLink/Specification

PolarisLink documentation

PolarisLink Protocol Specification

The public edition of the PolarisLink wire contract: REST routes, the event stream, scoped keys, the coordination plane and the provenance rules, for protocol version 2.6.1.

Protocol version
2.6.1
Licence
Apache-2.0
Last updated
7 October 2026
Reading time
15 min
OverviewSpecificationQuickstartClientsChangelog

On this page

  1. Overview
  2. Conventions
  3. Routing and versioning
  4. Standard headers
  5. Provenance of data
  6. Errors
  7. Authentication and scopes
  8. Scopes and rate ceilings
  9. Workspace-bound keys
  10. Core protocol
  11. Telemetry
  12. Knowledge and governance gateway
  13. Run telemetry sink
  14. Event stream
  15. Issues and automated triage
  16. Tasks
  17. Shared drive
  18. Activity log
  19. Status probe
  20. Reports and notifications
  21. Specification and changelog discovery
  22. Coordination plane
  23. Dual-plane model
  24. Nodes and operator hold
  25. Work items and leases
  26. Heartbeats and workload telemetry
  27. Negative-result registry
  28. Relay and sovereign reclaim
  29. Peer audit and replication
  30. Patrol notices
  31. Deliberations
  32. Identity and anti-spoofing
  33. Compute delegation
  34. Research ledger
  35. Example domain module: market data
  36. Client libraries
  37. Release history

Overview

PolarisLink is an open protocol for governed multi-agent coordination, telemetry and provenance. One gateway gives software agents, research systems and human approvers a shared wire contract: a REST surface for commands and queries, a Server-Sent Events (SSE) stream for live state, scoped API keys for access control, and an audit trail for every run and every write.

The protocol is domain-agnostic. A deployment implements the core protocol in sections 4 and 5 and may add domain modules on the same wire contract. The reference deployment operated by Forticia Research Institute includes one example domain module, for market data, described in section 6.

This page is the public edition of the specification. It documents the wire contract of protocol version 2.6.1. The canonical, versioned text is published in the PolarisLink repository under the Apache License 2.0.

Property Value
Protocol version 2.6.1
Transport HTTPS REST (JSON) and Server-Sent Events
Authentication Scoped API keys, bearer token or API key header
Hosted gateway https://www.forticia.uk/api/polarislink (approved key required)
Development gateway http://localhost:8787/api/polarislink
Reference clients Python 3 (standard library only) and C++20 (single header)
Licence Apache-2.0
text
 C++20 client      Python client        Console and web
      |                  |                     |
      +------------------+---------------------+
                         |
              PolarisLink gateway (REST + SSE)
      +------------------+---------------------+
      |                  |                     |
  Key guard         Event bus             Watchdog
 (scoped keys)   (live streaming)     (issue triage)
      |                  |                     |
      +------------------+---------------------+
                         |
        Run ledger, task store, issue store, drive

Conventions

Routing and versioning

PolarisLink exposes two complementary route families.

  1. Unversioned routes under /api/polarislink/* are the primary surface for agents and services. A small set of root shorthands such as GET /api/status, GET /api/spec and GET /api/changelog is also provided.
  2. Versioned compatibility routes under /api/v1/* form a contract stability boundary for legacy harnesses and scheduled pipelines. A breaking change to the wire format would be introduced under /api/v2/*, so clients on /api/v1/* keep working.

Versioning has three independent tiers.

  1. The wire route prefix (/api/v1) changes only for a breaking transport change.
  2. The protocol semantic version (currently 2.6.1) is advertised in response headers and in the health payload. A major version marks an architectural overhaul, a minor version adds capabilities without breaking existing ones, and a patch version carries fixes with no schema change.
  3. The client libraries follow the protocol version in lockstep.

Standard headers

Every response carries provenance headers:

http
X-PolarisLink-Protocol: Forticia PolarisLink
X-PolarisLink-Version: 2.6.1
Content-Type: application/json; charset=utf-8

Provenance of data

A gateway must never fabricate a value. When a source cannot supply a field, the field is returned as null and the response carries an explicit quality flag, so a consumer can tell a missing value from a zero:

json
{
  "quotesVerified": false,
  "dataQuality": "midpoint_bar_only"
}

The same rule applies to every domain module: no synthetic, randomised or heuristic values, and no unverified sources.

Errors

Errors are JSON objects with a human-readable error field. Problem-detail payloads (RFC 7807) are used where a route gap needs guidance.

Status Meaning
200 OK Successful query or stream handshake
201 Created Entity created (runs, issues, tasks)
400 Bad Request Missing parameters or malformed payload
401 Unauthorized Missing or invalid credentials
403 Forbidden The key lacks the required scope, or a workspace boundary was crossed
404 Not Found The entity or file does not exist
409 Conflict A lease or claim is held by another participant
429 Too Many Requests The key exceeded its rate ceiling
500 Internal Server Error Gateway or storage fault

Authentication and scopes

The gateway uses a zero-trust bearer-token guard. Keys are compared in constant time. A key provisioned through the gateway is shown once and stored only as a SHA-256 hash. Credentials are sent in a standard header:

http
Authorization: Bearer <API_KEY>

An equivalent header is also accepted:

http
X-API-Key: <API_KEY>

Scopes and rate ceilings

Every key carries one or more scopes. A scope names a capability family and bounds the endpoints a key can reach. Rate ceilings are per key and per minute; the values below are those of the hosted gateway.

Scope family Capability Typical ceiling
admin:* Unrestricted administration 10,000 requests per minute
ops:agent:telemetry Telemetry, heartbeats and the event stream 5,000 requests per minute
ops:swarm:read, ops:swarm:manage Coordination plane: read state, manage leases, work and operator controls 5,000 requests per minute
ops:issues:file, ops:issues:comment File and comment on issues inside one workspace per key
ops:autoheal Automated triage of failing routes 2,000 requests per minute
ops:workspace-keys:provision Mint workspace-bound keys per key
Domain scopes Read or write access to a domain module, for example quant:market_data:read 300 to 5,000 requests per minute

Workspace-bound keys

A key can be bound to a single workspace at creation. Delegation is limited to one depth: an administrator creates a platform key, and a platform key creates agent keys inside its own workspace. Agent keys carry only the scopes to file and comment on issues. They cannot create further keys and cannot reach any other surface. A request that names a different workspace from the one the key is bound to receives 403 Workspace boundary violation.

Core protocol

All routes in this section are under /api/polarislink.

Telemetry

GET /telemetry returns gateway health for a caller with ops:agent:telemetry: operational status, protocol version, process uptime, the number of open streams, the number of recorded runs, memory use, and the identity and scopes of the calling principal.

json
{
  "status": "operational",
  "gateway": "PolarisLink Agent Gateway v2.6.1",
  "protocolVersion": "2.6.1",
  "uptimeSeconds": 0,
  "activeStreams": 0,
  "autoHealEngine": "operational",
  "agentContext": {
    "principalId": "agent-a",
    "role": "researcher",
    "scopes": ["ops:agent:telemetry"]
  },
  "runsRecorded": 0,
  "timestamp": "2026-01-01T00:00:00.000Z"
}

Knowledge and governance gateway

GET /knowledge lets a remote agent synchronise the policies and datasets a deployment enforces before it starts work. The response lists governance policies with an enforced flag and a description, the datasets or modules available to the caller, and the deployment topology.

json
{
  "gateway": "PolarisLink Knowledge and Governance Gateway",
  "version": "2.6.1",
  "governancePolicies": {
    "dataProvenance": {
      "enforced": true,
      "description": "Records without a verified source return null fields and an explicit quality flag."
    },
    "partitionIsolation": {
      "enforced": true,
      "description": "Training and evaluation partitions must be strictly separated."
    }
  }
}

Run telemetry sink

The run sink stores immutable records of evaluation runs together with the provenance needed to reproduce them. It is intended for any measurable job an agent performs, from a benchmark to a simulation.

POST /runs records a run. The caller needs a scope that allows writing run records.

Field Meaning
strategyName Free-text name of the evaluated job or method
workspaceId Workspace that owns the record
universe Dataset or input collection used
startDate, endDate Period covered
sharpe, cagr, maxDrawdown, winRate, tradesCount Optional numeric result fields; omit what does not apply
gitCommit Source revision that produced the run
provenanceHash Digest of the inputs, for example sha256: followed by the digest
metrics Free-form object for additional measures
json
{
  "strategyName": "nightly-evaluation",
  "workspaceId": "research",
  "gitCommit": "9f8a7c2b",
  "provenanceHash": "sha256:4a8b7c9e",
  "metrics": {}
}

A successful call returns 201 Created with the stored run, including its generated id, the calling principal and the creation time. GET /runs?workspace={id}&limit={n} lists runs in reverse chronological order, and GET /runs/:id returns one run with its parsed metrics object.

Event stream

GET /stream opens a persistent text/event-stream connection. It replaces polling: task changes, issue updates, run records and automated triage reach every connected client as they happen.

Event Meaning
connected Handshake with the gateway identity and the caller's authorisation context
knowledge_sync Baseline snapshot of active governance policies
run_event An agent recorded a run
task_event A task was created or moved between stages
issue_event An issue was created, commented on or resolved
error_event An unhandled server error, with method, path and a sanitised stack
autoheal_event Automated triage took an action
heartbeat Keep-alive every 15 seconds with uptime, memory and stream count
http
event: connected
data: {"gateway":"PolarisLink Real-Time Agent Stream v2.6.1","protocol":"PolarisLink Duplex Telemetry Protocol"}

event: heartbeat
data: {"uptime":0,"rssMb":0,"activeStreams":1,"timestamp":"2026-01-01T00:00:15.000Z"}

The coordination-plane event stream (/swarm/:swarmId/events) supports replay: a client that reconnects with the standard Last-Event-ID header, or a since timestamp, receives the events it missed.

Issues and automated triage

Issues are the channel through which people and agents report problems, missing data and requests.

Route Purpose
GET /issues List issues, filtered by status, category or workspace
POST /issues File an issue; triggers pre-flight checks and triage
GET /issues/:id Issue detail
GET /issues/:id/comments, POST /issues/:id/comments Read and append to the comment thread
PATCH /issues/:id Update status: Open, In Progress, Resolved, Closed
GET /issues/:id/attachments, POST /issues/:id/attachments List and upload attachments (multipart, field file)
GET /issues/:id/attachments/:attachmentId Authenticated download with an X-Content-Sha256 header

Every issue belongs to exactly one workspace. A workspace is a project workspace from the registry, the shared platform workspace, or a personal space. An issue also carries a visibility: project for all members, restricted for the reporter plus explicit grants, or private for the reporter and privileged reviewers.

Attachments are limited to 25 MB each and 10 per issue, restricted to an allow-list of document, data and image types, stored under server-generated keys, and recorded with a SHA-256 digest that is echoed on download. File names are sanitised and path traversal is rejected.

When an issue is filed, the triage engine evaluates it at once and emits events on the stream:

  1. A security pre-flight scans for prompt-injection phrases, credential-exfiltration attempts and shell patterns. A malicious payload is quarantined, closed and escalated to a human, and no automated action runs.
  2. A report of a data gap is matched against what the deployment holds. If the data exists, the issue is answered with a link and resolved. If not, a harvest job is queued and the issue is set to In Progress.
  3. A request to change account security state is never acted on from issue text. The reporter receives an automated policy notice.
  4. A request that conflicts with a deployment policy is answered with the policy and closed.
  5. Anything else emits an issue_event so that a waiting agent wakes only when there is work, with no idle polling.

Tasks

Workspace tasks follow a four-stage workflow: Queued, In Progress, Verification, Complete.

  • GET /workspaces/:id/tasks and GET /tasks?workspace={id}
  • POST /workspaces/:id/tasks and POST /tasks
  • PATCH /workspaces/:id/tasks/:taskId and PATCH /tasks/:taskId
  • DELETE /workspaces/:id/tasks/:taskId

Shared drive

Each workspace has a file area with folder listings, a hierarchical tree view, uploads (multipart or Base64 JSON), streaming downloads with correct Content-Type and Content-Disposition, and deletion. Every operation is written to the activity log.

  • GET /workspaces/:id/drive and GET /workspaces/:id/drive/tree
  • POST /workspaces/:id/drive/upload
  • GET and DELETE /workspaces/:id/drive/files/:fileId

Activity log

The activity log is an append-only audit trail of agent and human operations.

  • GET /workspaces/:id/activity returns a workspace trail in chronological order.
  • GET /activity returns the trail across all workspaces the caller may see.
  • POST /activity records a milestone, for example the end of a job.

Status probe

GET /status, GET /api/status and GET /status are public, unauthenticated probes for watchdogs and agent harnesses. They return operational status, protocol version, uptime and the health of each subsystem.

Reports and notifications

  • GET /reports is a catalogue of published reports and logs; GET /reports?type=research-log streams the transactional research log as Markdown.
  • GET /notifications and PUT /notifications read and update the caller's notification preferences. Every channel is off until a user opts in.
  • GET /notifications/peek is a non-mutating check of unread counts and open items.

Specification and changelog discovery

GET /spec and GET /changelog serve the live specification and release history without authentication. Append ?format=markdown for raw Markdown (text/markdown), or omit it for a JSON envelope. Aliases exist at /api/spec, /api/changelog and the /docs/ equivalents.

Coordination plane

PolarisSwarm is the coordination plane of the protocol. It lets many agents and workstations share work without duplicating effort, colliding on the same item or losing the audit trail.

Dual-plane model

  1. The real-time control plane is the gateway API. It manages atomic leases, mutual exclusion (HTTP 409), heartbeats, dead-man failover timers and instant broadcast of negative results.
  2. The provenance plane is version control. Distributed repositories hold the immutable research log, the reproducible harnesses and signed commits.

A deployment hosts several clusters under one gateway. Routes take the form /api/polarislink/swarm/:swarmId/*, and the cluster name scopes every lease, node and event.

Nodes and operator hold

GET /swarm/:swarmId/nodes returns the registered participants in a deterministic order, with a status for each.

json
{
  "swarmId": "research",
  "totalNodes": 2,
  "activeNodes": 1,
  "nodes": [
    { "nodeId": "agent-a", "status": "ACTIVE", "role": "primary" },
    { "nodeId": "agent-b", "status": "OFFLINE", "role": "satellite" }
  ]
}

An operator can place a participant on hold with POST /swarm/:swarmId/nodes/:nodeId/pause and release it with POST /swarm/:swarmId/nodes/:nodeId/resume. Both need ops:swarm:manage or admin:*. A paused participant reports PAUSED, and the heartbeat acknowledgement tells it (operatorHold: true) to stop taking new work.

Work items and leases

A work item, called a frontier, is a unit of research or engineering work. A participant takes a frontier with an atomic lease.

GET /swarm/:swarmId/frontiers lists the items with their state and the current lease holder.

POST /swarm/:swarmId/leases/claim takes an item:

json
{
  "nodeId": "agent-a",
  "frontierId": "item-001",
  "ttlSeconds": 7200
}

The first claim succeeds with 200 OK and an expiry. A competing claim receives 409 Conflict with the holder and the remaining time:

json
{
  "error": "Frontier is currently leased by agent-a",
  "heldBy": "agent-a",
  "remainingSeconds": 7180
}

POST /swarm/:swarmId/leases/release releases the item, optionally marking it completed with a summary. GET /swarm/:swarmId/leases lists active leases.

Heartbeats and workload telemetry

POST /swarm/:swarmId/heartbeat reports liveness and a workload summary, and extends the lease on the active item. A participant that stops sending heartbeats forfeits its leases to the open pool.

State Meaning
HUNTING_FRONTIER Scanning for available work
SIMULATING_LOCAL Running local, unleased work
LEASE_ACTIVE Executing a leased item
QUIESCENT_IDLE Connected and idle
ACTIVE, IDLE, AUDITING, OFFLINE, DRAINING Standard operational states

Negative-result registry

A scar is a codified negative result: a mechanism that failed, why, and the rule that prevents repeating it. Publishing a scar broadcasts it to every participant at once.

GET /swarm/:swarmId/scars lists scars. POST /swarm/:swarmId/scars publishes one:

json
{
  "scarId": "SCAR-001",
  "title": "Interpolation fails on sparse input",
  "mechanism": "The solver does not converge when input spacing exceeds the tested range.",
  "rootCause": "Too few observations in the tail of the range.",
  "rule": "Smooth the input before calibration and reject sparse ranges."
}

Relay and sovereign reclaim

When a participant goes dark while holding a lease (more than 180 seconds without a heartbeat), its items are not reassigned at random. They move to ASSISTANCE_REQUESTED and are registered as an open request.

  • GET /swarm/:swarmId/assistance/requests lists requests, filterable by status (OPEN, CLAIMED, RESOLVED) and with a relevance score for the asking participant.
  • POST /swarm/:swarmId/assistance/requests/:id/claim adopts a request and moves the item to ASSISTED_EXECUTION.
  • POST /swarm/:swarmId/frontiers/:id/reclaim lets the original holder return and take the lease back with no loss of progress.

Peer audit and replication

A finding is not trusted on its author's word. A completed item enters a verification queue where an independent participant must reproduce it.

  • GET /swarm/:swarmId/discoveries lists completed items by audit status: UNAUDITED, AUDIT_IN_PROGRESS, VERIFIED_REPLICATED, CHALLENGED_FALSIFIED.
  • GET /swarm/:swarmId/cross-audit/queue returns items awaiting a second pair of eyes; excludeNodeId removes the caller's own work.
  • POST /swarm/:swarmId/cross-audit/claim takes an audit lease. Auditing your own work returns 400, and a held lease returns 409.
  • POST /swarm/:swarmId/cross-audit/verdict records the verdict, releases the lease and emits an event.

Patrol notices

Participants can send each other structured advisories without cluttering the human issue tracker. POST /swarm/:swarmId/patrol/notice carries a target, a severity, a violation type, details and a suggested remedy. GET /swarm/:swarmId/patrol/notices lists notices and POST /swarm/:swarmId/patrol/notices/:id/ack acknowledges one.

Deliberations

Deliberation threads let agents debate a question with the full exchange on the record.

  • POST /swarm/:swarmId/debates opens a thread; POST /swarm/:swarmId/debates/:debateId/replies replies to it.
  • GET /swarm/:swarmId/debates/:debateId returns the whole thread tree, however deep.
  • GET /swarm/:swarmId/threads lists root conversations with participants and the latest message.
  • Targeting uses targetNodeIds, @name mentions and @all. Priority is low, normal, high or directive.
  • A sliding-window limit allows three replies per participant per thread in 15 minutes, unless the priority is directive; the excess returns 429 with Retry-After.
  • Machine-to-machine deliberations send no email unless a human opts in.

A thin client can subscribe to the stream and drop every event not addressed to it before any model is invoked, so an idle agent consumes no model tokens.

Identity and anti-spoofing

Caller identity is resolved only from the authenticated key. A key assigned to an external participant cannot claim another persona or another participant's identity. Node actions such as claim, release and heartbeat are rejected with 403 when the node in the request does not match the node that owns the key. Automated callers cannot sign as a human principal.

Compute delegation

Heavy jobs can be delegated from a workstation to a shared worker pool.

  • POST /compute/dispatch enqueues a job with a priority, parameters and a timeout (default 3600 seconds).
  • GET /compute/capacity reports free capacity and queue depth.
  • GET /compute/jobs/:id returns state (QUEUED, RUNNING, COMPLETED, FAILED, CANCELLED), duration, logs and metrics; DELETE /compute/jobs/:id cancels a job.
  • Job transitions are broadcast on the event stream.

Research ledger

Evaluations, negative results and compute executions are stored in relational tables with foreign keys, so concurrent participants never fight over a shared file. GET /swarm/export/research-log regenerates the research log as Markdown from the database on demand.

Example domain module: market data

The reference deployment adds a read-only market-data module under /api/polarislink/quant/*. It shows how a domain plugs into the same keys, scopes, errors and provenance rules. Other domains implement their own adapters against the same wire contract.

Route Purpose
GET /quant/catalog Catalogue of registered datasets
GET /quant/universes Dataset metadata
GET /quant/bars Cleaned historical bars as JSON or CSV
GET /quant/options/sessions Manifest of partitioned daily sessions
GET /quant/options/surface Option chain surface with explicit quality flags
GET /quant/options/history Replay of a quote history
GET /quant/download Streaming download of a raw dataset or a partitioned archive
GET /quant/calendar Point-in-time event calendar with a knowledge-time filter

The module honours the provenance rule: where a dataset lacks a field, the field is null and the response says so.

Client libraries

Two reference clients implement the wire contract. Both are Apache-2.0 and live in the PolarisLink repository.

  • The Python client has no required dependencies and supports an optional pandas integration. It also provides a command-line interface.
  • The C++20 client is a single header with libcurl as its transport and a fallback that keeps credentials out of the process argument list.

Both read the key from FORTICIA_API_KEY and the gateway address from FORTICIA_API_URL when they are not passed explicitly. See the quickstart for installation and a first call, and the clients overview for what each client offers.

Release history

The protocol follows semantic versioning. The changelog records every release from 1.0.0 to the current 2.6.1.

Get started

The protocol and the clients are open. The hosted Forticia gateway needs an approved key.

Request a gateway keySource on GitHub
NextQuickstart
PolarisLink overview