---
title: "Link units"
description: "Link an existing folder of .10x.json symbol units into a single .10x.tar library, with no source scan."
icon: material/link-variant
---

Link a folder of `.10x.json` symbol units from a prior compile into a single `.10x.tar` library, with no source scan.

It is the same [Compiler app](../../../compiler/) invoked with link-only arguments: the units folder is also the output folder and no source is mounted, so the engine reuses the units already on disk and [merges them into the library](../../../../compile/link/).

Use it to:

- re-link after editing or pruning units
- assemble a library from a units tree built piecemeal
- rebuild a library from the output folder of a prior [`log10x_compile`](compile.md)

Same wait shape as compile: the link waits inline up to `max_wait_ms` (default 45s). Linking is usually fast, so it normally returns the finished library in one call.

A very large units tree returns a running `job_id` to poll with [`log10x_compile_status`](compile-status.md), and `max_wait_ms: 0` returns the `job_id` immediately.

## :material-code-braces: Example

!!! tenx-ask "You"

    I pruned the units folder. Re-link it into a library.

!!! tenx-answer "Log10x"

    Linked 412 units into `symbols.10x.tar` (3.4 MB) in 6s. No source scan, no new files traversed. Symbols by type: class 1,180, log 642, exec 410, enum 96.

## :material-chat-question-outline: More to ask

- *"link `/work/units` and call the library `payments`"*
- *"rebuild the library from my last compile's output folder"*
- *"the units tree is huge, kick off the link and give me a job_id"*

## :material-check-decagram-outline: Prerequisites

The Compiler flavor, docker-first: `auto` and `docker` pull `log10x/compiler-10x`, and `local` runs a Compiler-flavor `tenx`. The Runtime flavor is refused.

This is the CLI tier, so it needs no Kubernetes, deployed app, or Log10x account.

`units_path` must hold at least one `.10x.json` unit from a prior [`log10x_compile`](compile.md). An empty folder is refused with nothing to link.

## :material-code-json: Schema and samples

??? tenx-input-example "Input example"

    Re-link a pruned units folder into a named library.

    ```json
    {
      "units_path": "/work/symbols-out",
      "library_name": "payments"
    }
    ```

??? tenx-input-schema "Input schema"

    Agent-facing JSON Schema (the canonical shape the MCP server publishes via `tools/list`):

    ```json
    {
      "type": "object",
      "properties": {
        "units_path": {
          "type": "string",
          "description": "Absolute path to a folder of .10x.json symbol units (produced by a prior compile) to link into a single .10x.tar library. Traversed recursively; the existing units are merged with NO source re-scan, and the .10x.tar is written into this same folder."
        },
        "library_name": {
          "type": "string",
          "default": "symbols",
          "description": "Base name for the linked .10x.tar and the runtimeName. Sanitized to [A-Za-z0-9_.-]."
        },
        "mode": {
          "type": "string",
          "enum": ["auto", "docker", "local"],
          "default": "auto",
          "description": "Execution backend, same contract as log10x_compile: `auto` prefers the Compiler image, `docker` forces it, `local` uses a Compiler-flavor tenx. The Runtime flavor is refused."
        },
        "timeout_ms": {
          "type": "integer",
          "minimum": 10000,
          "maximum": 3600000,
          "default": 600000,
          "description": "Hard cap on link wall time in ms. Default 600,000 (10 min). Linking is much faster than scanning, but a very large units tree can still take minutes."
        },
        "max_wait_ms": {
          "type": "integer",
          "minimum": 0,
          "maximum": 300000,
          "default": 45000,
          "description": "How long to wait inline (ms) for the link to finish before handing back a job_id to poll. Default 45,000 (45s). Linking usually finishes inside this and returns the library in ONE call. A very large units tree returns a running job_id you poll with log10x_compile_status. 0 = fire-and-forget."
        }
      },
      "required": ["units_path"],
      "additionalProperties": false
    }
    ```

    Source: [`src/tools/compile-link.ts`](https://github.com/log-10x/log10x-mcp/blob/main/src/tools/compile-link.ts).

??? tenx-output-example "Output example"

    Representative envelope for a fast link that finished inside `max_wait_ms`. The bounded-sync path returns the [`log10x_compile_status`](compile-status.md) readout the moment the link completes, so the shape matches that tool: `data.payload.job_status` is `completed`, with the produced units, the linked library, and the link diagnostics. The `diagnostics.scan_health` block is null on a link (no source scan), and `link_report` populates once the `compiler-10x` image carries the engine diagnostics change.

    ```json
    {
      "schema_version": "1.0",
      "schema_epoch": "2026-05-25",
      "tool": "log10x_compile_status",
      "generated_at": "2026-06-15T09:12:04.118Z",
      "view": "summary",
      "status": "success",
      "summary": {
        "headline": "Link job `7b2e9c41-...` done: 412 units → /work/symbols-out/payments.10x.tar (3.4 MB)."
      },
      "data": {
        "status": "success",
        "decisions": { "threshold_used": null, "threshold_basis": "default" },
        "source_disclosure": {},
        "scope": {
          "window": "payments_compile",
          "window_basis": "explicit",
          "candidates_count": 412,
          "candidates_usable": 1
        },
        "payload": {
          "job_id": "7b2e9c41-3f5a-4d8e-9b21-6c0f1a2d7e44",
          "job_status": "completed",
          "mode": "docker",
          "image": "log10x/compiler-10x",
          "exit_code": 0,
          "elapsed_ms": 6240,
          "timed_out": false,
          "sources": "link /work/symbols-out",
          "output": {
            "folder": "/work/symbols-out",
            "unit_count": 412,
            "empty_unit_count": 0,
            "library_files": [
              { "path": "/work/symbols-out/payments.10x.tar", "bytes": 3565158 }
            ]
          },
          "diagnostics": {
            "results_available": true,
            "phases": [
              {
                "operation": "link",
                "status": "ok",
                "traversed_files": 412,
                "scanned_files": 0,
                "output_files": 1,
                "warns": 0,
                "errors": 0
              }
            ],
            "scan_health": null,
            "link_report": {
              "merged_files": 412,
              "skipped_files": 0,
              "excluded_by_folder": 0,
              "excluded_by_file_name": 0,
              "merged_repos_count": 1,
              "non_merged_repos_count": 0,
              "symbols_by_type": { "class": 1180, "log": 642, "exec": 410, "enum": 96 },
              "symbols_excluded_by_type": 0
            }
          },
          "log_tail": []
        },
        "human_summary": "Link job 7b2e9c41-... completed via docker in 6s: 412 symbol units, linked to /work/symbols-out/payments.10x.tar (3.4 MB). No files failed to scan. Linked 412 unit files; symbols by type: class 1180, log 642, exec 410, enum 96."
      },
      "actions": [
        {
          "tool": "log10x_validate",
          "args": { "extra_args": [["symbolPaths", "/work/symbols-out"]] },
          "reason": "smoke-test the compiled library against a few sample event lines (supply input_lines)"
        }
      ],
      "truncated": false,
      "warnings": []
    }
    ```

    A units tree too large to link inside `max_wait_ms`, or a call with `max_wait_ms: 0`, returns the handoff envelope instead, with `data.payload.job_status: "running"` and a `log10x_compile_status` action carrying the `job_id`.

??? tenx-output-schema "Output schema"

    The `data` block inside the [chassis envelope](../index.md). On the bounded-sync completion path the payload is the [`log10x_compile_status`](compile-status.md) shape:

    ```typescript
    interface CompileLinkPayload {
      job_id: string;
      job_status: 'running' | 'completed' | 'failed' | 'timed_out';
      mode: 'docker' | 'local';
      image: string | null;
      exit_code: number | null;
      elapsed_ms: number;
      timed_out: boolean;
      sources: string;
      output: {
        folder: string;
        unit_count: number;
        empty_unit_count: number;
        library_files: Array<{ path: string; bytes: number }>;
      };
      diagnostics: {
        results_available: boolean;
        phases: Array<{
          operation: string | null;
          status: string | null;
          traversed_files: number | null;
          scanned_files: number | null;
          output_files: number | null;
          warns: number | null;
          errors: number | null;
        }>;
        // null on a link (no source scan).
        scan_health: {
          files_failed: number;
          failed_by_language: Record<string, number>;
          failure_samples: Array<{ name: string; language: string; reason: string }>;
        } | null;
        // Populated once the compiler-10x image carries the engine
        // diagnostics change; null otherwise (graceful degradation).
        link_report: {
          merged_files: number;
          skipped_files: number;
          excluded_by_folder: number;
          excluded_by_file_name: number;
          merged_repos_count: number;
          non_merged_repos_count: number;
          symbols_by_type: Record<string, number>;
          symbols_excluded_by_type: number;
        } | null;
      };
      log_tail: string[];
    }
    ```

    When the link overruns `max_wait_ms`, the handoff payload is smaller: `{ job_id, job_status: 'running', mode, image, library_file, runtime_name, sources, started_at, timeout_ms, log_file, units_path, unit_count }`. Poll [`log10x_compile_status`](compile-status.md) with `job_id` for the completed shape above.

    Envelope-level fields the agent should also read: `status` (top-level mirror of `data.status`), `summary.headline` (1-line answer), `data.human_summary` (the quotable plain-English summary), `actions[]` (next-call chain hints as `{tool, args, reason}`), `truncated`, and `schema_epoch`.
