TensorLine documentation.
TensorLine is a Go server on PostgreSQL that is the system of record for agent plans, tasks, documents, reviews, and worktrees. Agents reach it over MCP; operators drive it through two local CLIs. There is no HTTP API or web UI yet — that is M11. TensorLine is in Closed beta and is not a GitHub replacement.
What TensorLine is today.
TensorLine is a Go server backed by PostgreSQL that holds agent plans, tasks, documents, findings, reviews, agent runs, and worktrees as live rows — the system of record for agent-driven engineering. It is reached two ways: agents connect over MCP at /mcp, and operators run two local CLIs (tensorline-admin and tensorline-worktree).
There is no HTTP API or web UI yet — that is M11. The OpenAPI contract exists and is frozen, but it is not served; do not expect a REST surface or a frontend in this release. TensorLine is in Closed beta, and it is not a GitHub replacement — source control and pull requests stay where they are. This page documents the pinned version 992010d2. Milestones M0 through M7 and M9 are complete; interfaces can still change before general availability.
The objects TensorLine tracks.
- Organization — the tenant. Every credential is bound to one organization; a request for another tenant's id and a request for an id that does not exist return the identical 404, so existence never leaks across tenants.
- Principals — humans, agents, and services. Human principals carry a role of
owner,admin, ormember; an agent's or service's authority is derived, not requested. - Scoped bearer tokens — an agent authenticates with a token that names its tenant and principal. Tokens are stored hashed; the secret is shown once at issue time.
- Work items, documents, findings, reviews, agent runs, and worktrees — the domain. Every mutation of a tenant table writes an
eventrow by a database trigger, so the audit trail is a property of the schema rather than of convention.
Build the binaries.
TensorLine needs Go 1.26 and PostgreSQL 16 or 17 binaries (no Docker). make build compiles all four binaries into ./dist/:
The four binaries are tensorline-server (the MCP and worktree listener), tensorline-migrate (forward-only migrations plus first-owner bootstrap), tensorline-admin (the privileged control plane), and tensorline-worktree (the on-host worktree CLI). tensorline-server takes only -version.
A throwaway dev cluster.
Four make targets stand up a throwaway PostgreSQL cluster over a UNIX socket under .dev-cluster/ — no Docker, no TCP port:
make dev-db writes .dev-cluster/env, which exports the platform TP_* variables plus TensorLine's TL_BOOTSTRAP_*, admin, and artifact-store variables.
The owner DSN and the application DSN are separate on purpose. Migrations run as the schema OWNER through TP_MIGRATE_DATABASE_DSN; the server runs as the de-privileged tensorline_app through TP_DATABASE_DSN. tensorline_app holds no DDL privilege, so it cannot alter the tables whose row-level-security policies constrain it — one shared DSN would hand the request path the power to drop its own policies.
make dev-db also sets the PostgreSQL logging settings the server requires. The two that matter are log_parameter_max_length and log_parameter_max_length_on_error: their PostgreSQL default of -1 logs bind parameters in full, so the server refuses to start unless both are set to 0. A cluster missing them looks like a broken binary, not a hardening suggestion.
Environment variables.
Configuration is entirely environment variables. Every *_REF names a reference to a secret in your backend, never an inline password; a DSN carrying an inline password for the admin credential is refused. The server listens on loopback (127.0.0.1:8080) by default and has no built-in TLS — put your own TLS terminator in front of it.
| Variable | Used by | Default / required | Notes |
|---|---|---|---|
TP_ENVIRONMENT | server | Required | Deployment environment label (for example production). |
TP_SERVICE_NAME | server | tensorline | Telemetry identity. It is tensorline; the sibling default is refused. |
TP_SECRETS_BACKEND | server | Required | Which secrets backend resolves the *_REF references (for example file). |
TP_DATABASE_APP_ROLE | server | tensorline_app | The de-privileged login the request path uses. tensorplane_app is refused. |
TP_DATABASE_DSN | server | Required | DSN for tensorline_app. No inline password — the password comes from the ref. |
TP_DATABASE_PASSWORD_REF | server | Required | Reference (not a secret) to the app-role password in your secrets backend. |
TP_MIGRATE_DATABASE_DSN | migrate | Required | DSN naming the schema OWNER — a distinct credential from TP_DATABASE_DSN. |
TL_LISTEN_ADDR | server | 127.0.0.1:8080 | Loopback by default. Put your own TLS terminator in front; the server has no built-in TLS. |
TL_ARTIFACT_STORE_DIR | server | /var/lib/tensorline/artifacts | Reclamation archives land here. Point it at a durable, backed-up volume — never under /tmp. |
TL_ADMIN_DATABASE_DSN | admin | Required for tensorline-admin | The per-operator login. Separate from TP_DATABASE_* by design; inline password refused. |
TL_ADMIN_DATABASE_PASSWORD_REF | admin | Required for tensorline-admin | Reference to the operator login's password. |
TL_RECLAIM_DATABASE_DSN | server | Optional | Enables the stream-boundary reclamation sweep, with its own reclaim pool. With no reclaim DSN and password ref set, the server logs stream-boundary reclamation is NOT configured and does not reclaim expired boundaries. |
TL_RECLAIM_DATABASE_PASSWORD_REF | server | Optional | Reference to the reclaim pool's password. |
TL_RECLAIM_INTERVAL | server | Optional (default 5m) | Sweep interval, a Go duration. Defaults to 5m once TL_RECLAIM_DATABASE_DSN and TL_RECLAIM_DATABASE_PASSWORD_REF are set; setting it alone, without the DSN, is refused at startup. |
TL_GITHUB_APP_ID | server (forge) | All-or-nothing | One of the three App credentials that enable the forge integration together; setting one or two is refused at startup. |
TL_GITHUB_API_BASE_URL | server (forge) | Optional (default https://api.github.com) | GitHub REST base; defaults to https://api.github.com and must be an https URL. Only meaningful with the three App credentials: setting the base URL alone, without them, is refused at startup as a partially configured forge. |
TL_GITHUB_APP_PRIVATE_KEY_REF | server (forge) | All-or-nothing | Reference to the GitHub App private key. One of the three App credentials that enable the forge integration together. |
TL_GITHUB_WEBHOOK_SECRET_REF | server (forge) | All-or-nothing | Reference to the webhook secret. One of the three App credentials that enable the forge integration together; enables /v1/webhooks/github. |
TL_FORGE_BUDGET_PER_SWEEP | server (forge) | Optional (default 250) | Reconcile budget per sweep, a whole number of requests. Defaults to 250 and must be at least 64 or startup is refused. Optional; takes effect only when the forge integration is enabled. |
TL_FORGE_RECONCILE_INTERVAL | server (forge) | Optional (default 5m) | How often the forge reconcile loop runs, a positive Go duration. Defaults to 5m. |
TL_FORGE_REPROCESS_INTERVAL | server (forge) | Optional (default 2m) | How often deferred forge objects are reprocessed, a positive Go duration. Defaults to 2m. |
The three GitHub App credentials — TL_GITHUB_APP_ID, TL_GITHUB_APP_PRIVATE_KEY_REF, and TL_GITHUB_WEBHOOK_SECRET_REF — are all-or-nothing: set all three to enable the GitHub App integration, or none; setting one or two is refused at startup. So is setting TL_GITHUB_API_BASE_URL on its own — it counts as a partial forge configuration. The remaining forge variables are optional and take their defaults (TL_GITHUB_API_BASE_URL https://api.github.com, TL_FORGE_BUDGET_PER_SWEEP 250 and at least 64, TL_FORGE_RECONCILE_INTERVAL 5m, TL_FORGE_REPROCESS_INTERVAL 2m) once it is enabled. When enabled, the webhook mounts at /v1/webhooks/github. The admin and reclaim credentials are deliberately separate logins from the server's, so "this deployment can run the privileged CLI" is a visible fact about a unit file rather than an inference.
When the server refuses to start.
tensorline-server fails closed. It prints tensorline-server: <err> and exits 1 when any of these hold:
- The database role is not de-privileged — the pool is opened as something other than
tensorline_app. FixTP_DATABASE_APP_ROLEandTP_DATABASE_DSN. - The operator role topology is wrong — the operator role grants are not as the schema expects. Provision
tensorline_operatorcorrectly. - PUBLIC holds EXECUTE on a privileged procedure — an omitted REVOKE. Revoke EXECUTE from PUBLIC on the control-plane procedures.
log_parameter_max_lengthorlog_parameter_max_length_on_erroris not0— set both to0.- The schema is behind — the startup privilege sweep resolves every procedure signature, so a binary whose migrations have not been applied refuses rather than serving against a stale schema. Run
tensorline-migratefirst.
The server shuts down gracefully on SIGINT or SIGTERM with a 5-second drain timeout. A per-IP rate limit runs before authentication.
Migrate, bootstrap, and provision operators.
tensorline-migrate requires TP_MIGRATE_DATABASE_DSN naming the schema OWNER (distinct from TP_DATABASE_DSN). Migrations are forward-only — there are no down migrations. It prints applied N migration(s); … and then bootstraps the first owner from four variables — all four or none, and a no-op once an owner exists:
TL_BOOTSTRAP_ORG_ID— the externally issued organization id.TL_BOOTSTRAP_ORG_NAME— the organization name.TL_BOOTSTRAP_OPERATOR_ROLE— the first operator's database login.TL_BOOTSTRAP_HUMAN_USER_ID— the first human user's id.
Principal lifecycle, token issuance, integration credentials, and gate policy are not reachable from the request path. They live behind tensorline-admin, which connects through TL_ADMIN_DATABASE_DSN and TL_ADMIN_DATABASE_PASSWORD_REF. Every subcommand takes -org <uuid>:
| Subcommand | What it does |
|---|---|
create-principal | Create a principal (-kind human|agent|service, -role for humans only). |
change-principal-role | Re-grade an existing human principal. |
disable-principal | Remove a principal's authority. |
delete-principal | Remove a principal entirely. |
issue-agent-token | Mint a bearer token for an agent or service principal (-principal -name -ttl). |
list-agent-tokens | Show an org's credentials and which still authenticate. |
reissue-agent-tokens | Replace credentials of every principal that cannot authenticate ([-dry-run] [-name]). |
revoke-agent-token | Destroy a bearer token. |
set-integration-credential | Record where an integration credential lives. |
set-org-policy | Change gate policy (review approval, minimum reviews, cycle budget). |
map-operator-login | Bind a database login to the principal it acts as (-db-role -principal). |
There is no --as flag. The acting operator is derived server-side from the database login you connect as, through the operator_login mapping. Provisioning an operator is two steps: create the database role (CREATE ROLE and GRANT tensorline_operator TO …, a cluster-global operation the schema owner must not be able to do), then bind it with map-operator-login, which refuses any role that is not correctly provisioned.
Create a principal and issue an agent token (placeholders only):
issue-agent-token prints the secret once to stdout and stores only its argon2id hash — capture it there.
The MCP surface.
Agents connect over Streamable HTTP on the single endpoint /mcp, presenting a scoped bearer token. The token format is tlagt.<org>.<prefix>.<secret> — it names the tenant before there is a row to read. Point a generic MCP client at your host with the token as a bearer credential (placeholders only — supply your own host and token, do not treat any one vendor's config schema as authoritative):
There are 20 tools. Every result is bounded — listings page with keyset cursors and documents come back in a byte window with an explicit truncated flag — so a response can never outgrow its declaration.
| Group | Tools |
|---|---|
| Read | tl_search, tl_get_work_item, tl_get_document, tl_check_readiness, tl_list_issues |
| Claim & heartbeat | tl_claim_task, tl_heartbeat, tl_release_task |
| Documents & reviews | tl_submit_document_revision, tl_request_review, tl_submit_review, tl_update_finding |
| Issues & escalation | tl_create_issue, tl_escalate |
| Runs | tl_start_run, tl_report_run, tl_report_run_result |
| Forge | tl_link_forge_object |
| Worktrees | tl_submit_worktree_scan, tl_propose_artifact_disposition |
Reclamation is not on the MCP surface: a bot may scan and propose dispositions, but it can never authorise reclamation, and the call is not offered here at all.
Reclaiming a worktree.
tensorline-worktree runs on the machine that holds the worktree, because the server cannot see a filesystem. It authenticates with a scoped bearer token and holds no database credential. Set TL_SERVER_URL and a token via TL_TOKEN_FILE (preferred) or TL_TOKEN:
The lifecycle is scan → state → reclaim (dry-run) → reclaim → restore. Nothing is ever deleted: reclamation archives the whole directory, hashes the bytes, re-walks to confirm, then performs exactly one rename(2) into quarantine — reversible while quarantine exists.
-dry-run archives, verifies, and re-walks, then stops before authorising — so "would this be allowed, and what is unmet" costs nothing. The real reclaim is refused unless the credential belongs to an admin or an owner; a bot or member may scan and propose only. If quarantine is on another filesystem the whole thing is refused — there is no copy-then-delete fallback.
The frozen OpenAPI contract (not yet served).
The OpenAPI document openapi/tensorline.yaml is frozen at 1.0.0-m11a — 57 paths, bearer-authenticated under https://{host}/api/v1. It is a frozen contract, not a served surface: there is no HTTP API yet (M11), so treat it as the shape the API will take, not something to call today.
| Route group | Paths |
|---|---|
| work-items | 11 |
| documents | 9 |
| maintenance | 8 |
| worktrees | 7 |
| agent-runs | 5 |
| auth | 3 |
| claims | 3 |
| escalations | 2 |
| stream-recovery-contexts | 2 |
| events / findings / inbox / issues / principal / search / stream-boundaries | 1 each |
The contract's events stream is documented as at-least-once: an event may be redelivered, and clients deduplicate on the envelope's event_id, never on the SSE transport id.
Migrate first, then deploy.
Apply tensorline-migrate before deploying any server or admin binary of that release. This is enforced, not remembered: a binary whose schema has not been applied refuses to start, and a previous release's binary cannot mint a credential against a newer schema.
Migration 0003_session.sql changes the bearer-token wire format from tlagt.<prefix>.<secret> to tlagt.<org>.<prefix>.<secret> and revokes every old token in the same transaction, recording one agent_token.revoked event per credential with reason = 'token_format_changed'. There is no compatibility window. Recovery is one runbook:
reissue-agent-tokens is idempotent and resumable, and each token is written to stdout before it is stored — so capture stdout. What this upgrade does not provide: no schema rollback (the migrator is forward-only), legacy credentials cannot be restored (their wire format is no longer parseable), and authentication is interrupted between the migration and the reissue — run it in a window where that is acceptable.
Common startup and CLI errors.
TP_MIGRATE_DATABASE_DSN is required— set it to the schema OWNER DSN, distinct fromTP_DATABASE_DSN.- Server refuses with a role error —
TP_DATABASE_APP_ROLEis nottensorline_app(the siblingtensorplane_appis refused). - Server refuses over logging — set
log_parameter_max_lengthandlog_parameter_max_length_on_errorto0on the cluster. no credential: set TL_TOKEN_FILE or TL_TOKEN— the worktree CLI has no token; set one of them.TL_SERVER_URLis not set — the worktree CLI cannot reach the server; export it.- Reclamation refused because quarantine is on another filesystem — move
-quarantineonto the worktree root's filesystem; there is no copy fallback. - Reclamation refused for a
botormembercredential — reclaim needs anadminorowner; bots may scan and propose only. - Log warning
stream-boundary reclamation is NOT configured— setTL_RECLAIM_DATABASE_DSN(and its password ref) to enable the sweep.
What is not in the Closed beta.
- A usable HTTP API or web UI — the contract is frozen but not served (M11).
- A GitHub replacement — source control and pull requests stay where they are.
- A hosted, multi-tenant SaaS sign-up.
- Forge integrations beyond github.com — no GitHub Enterprise Server, GitLab, or other third-party git hosts.
- External security-compliance certifications, customer-supplied model keys, or any availability or high-availability service-level guarantee.
- TLS built into the server, Docker images, or install packages beyond
make build. - Schema rollback or restoration of legacy-format credentials.
How to get into the Closed beta.
TensorLine is invite-only in the Closed beta. Request early access, or contact us; Closed beta participants receive access to the TensorLine repository.
How TensorLine is priced.
TensorLine is part of the single platform plan — €35 per contributing developer, billed on unique non-bot git authors whose work the platform touched, trailing 90 days. There is no separate TensorLine price. See billing for the full model.
Get early access to the platform.
Every product is included in one platform subscription. Request early access and we'll onboard your team hands-on — free while we build toward launch.