# nts-sources.yml: Format, Schema, and Purpose Explained

> Understand the nts-sources.yml format and purpose. This YAML file acts as the single source of truth for NTS servers, defining metadata and enabling automated NTP configurations.

- Repository: [Jauder Ho/nts-servers](https://github.com/jauderho/nts-servers)
- Tags: api-reference
- Published: 2026-03-04

---

**The [`nts-sources.yml`](https://github.com/jauderho/nts-servers/blob/main/nts-sources.yml) file is a YAML database that serves as the single source of truth for all Network Time Security (NTS) servers tracked by the repository, defining server metadata and enabling automated configuration generation for NTP daemons.**

The `jauderho/nts-servers` repository maintains a curated list of public NTS servers for secure time synchronization. At the heart of this project lies [`nts-sources.yml`](https://github.com/jauderho/nts-servers/blob/main/nts-sources.yml), a structured YAML file that catalogs every server with essential metadata including hostname, stratum, and geographical location. This central file drives the entire automated pipeline that generates configuration files for Chrony and ntpd-rs while keeping documentation synchronized.

## Understanding the nts-sources.yml Format

The [`nts-sources.yml`](https://github.com/jauderho/nts-servers/blob/main/nts-sources.yml) file uses a straightforward schema designed for both human readability and machine parsing. According to the source code in `jauderho/nts-servers`, the file organizes data under a top-level `servers` key containing an ordered list of server descriptors.

### YAML Schema and Required Fields

Each server entry in [`nts-sources.yml`](https://github.com/jauderho/nts-servers/blob/main/nts-sources.yml) is a mapping with the following fields (as defined in lines 1-14 of the file):

- **`hostname`**: String representing the DNS name. Supports plain text or Markdown link syntax (e.g., `"[time.cloudflare.com](https://time.cloudflare.com)"`).
- **`stratum`**: Integer indicating the NTP stratum level (lower values indicate higher accuracy).
- **`location`**: String describing the geographical location (country or city).
- **`owner`**: String identifying the organization or individual responsible for the server.
- **`notes`**: Optional string for additional remarks such as "Anycast" or "IPv4 and IPv6".
- **`vm`**: Boolean flag set to `true` if the server runs in a virtualized environment.

A minimal valid entry appears as:

```yaml
- hostname: time.cloudflare.com
  stratum: 3
  location: All
  owner: Cloudflare
  notes: Anycast
  vm: false

```

### File Organization Requirements

The file enforces **alphabetical grouping by country** to ensure predictable editing and automated processing. As specified in [`AGENTS.md`](https://github.com/jauderho/nts-servers/blob/main/AGENTS.md) (lines 3-6), new entries must be inserted into the appropriate alphabetical section, making the raw YAML structure scannable and version-control friendly.

## Core Purpose and Automation Pipeline

The [`nts-sources.yml`](https://github.com/jauderho/nts-servers/blob/main/nts-sources.yml) file functions as the **canonical definition** for trusted NTS servers. Rather than maintaining separate lists for documentation and configuration, all downstream artifacts derive from this single source.

### Configuration File Generation

The [`scripts/ntpServerConverter.py`](https://github.com/jauderho/nts-servers/blob/main/scripts/ntpServerConverter.py) script consumes [`nts-sources.yml`](https://github.com/jauderho/nts-servers/blob/main/nts-sources.yml) to produce three critical outputs:

- **[`chrony.conf`](https://github.com/jauderho/nts-servers/blob/main/chrony.conf)**: Chrony NTP daemon configuration generated by `generate_chrony_conf` (lines 59-77).
- **[`ntp.toml`](https://github.com/jauderho/nts-servers/blob/main/ntp.toml)**: ntpd-rs configuration generated by `generate_ntp_toml` (lines 86-106).
- **README tables**: Markdown documentation generated by `generate_markdown` (lines 21-44).

### Stratum Verification and Updates

To maintain accuracy, [`scripts/ntsUpdateServers.py`](https://github.com/jauderho/nts-servers/blob/main/scripts/ntsUpdateServers.py) reads the YAML file and queries each server using `ntpdate` or `ntpq`. The `update_stratum_values` function (lines 40-87) compares reported stratum values against the stored data and rewrites the file when discrepancies are detected.

### Agent-Driven Automation

The repository's automated agent workflow (defined in [`AGENTS.md`](https://github.com/jauderho/nts-servers/blob/main/AGENTS.md)) inserts new servers directly into [`nts-sources.yml`](https://github.com/jauderho/nts-servers/blob/main/nts-sources.yml) after validating NTS/NTP reachability. This ensures the central database remains current without requiring manual YAML editing for every new server.

## Practical Usage Examples

Working with [`nts-sources.yml`](https://github.com/jauderho/nts-servers/blob/main/nts-sources.yml) involves parsing Markdown-formatted hostnames, generating configurations, and updating metadata programmatically.

### Extracting Hostnames from Markdown Links

When processing the `hostname` field, scripts must handle both plain text and Markdown link formats. The [`scripts/ntsUpdateServers.py`](https://github.com/jauderho/nts-servers/blob/main/scripts/ntsUpdateServers.py) implementation (lines 28-44) uses regex extraction:

```python
import re

def extract_hostname(hostname_field):
    """
    Accepts plain text or Markdown links like 
    '[time.cloudflare.com](https://time.cloudflare.com)'
    Returns the raw hostname.
    """
    markdown_match = re.match(r'\[([^\]]+)\]', hostname_field)
    if markdown_match:
        return markdown_match.group(1)
    return hostname_field.strip()

```

### Adding a New Server Entry

To manually append a server, insert into the appropriate alphabetical section following the established schema:

```yaml
- hostname: "[time.example.de](https://time.example.de)"
  stratum: 2
  location: Germany
  owner: Example Corp
  notes: IPv4 and IPv6
  vm: false

```

This format mirrors entries found in lines 71-78 of the source file.

### Generating Configuration Files

Convert the YAML into usable NTP daemon configurations with:

```bash
python3 scripts/ntpServerConverter.py nts-sources.yml

```

This command writes [`chrony.conf`](https://github.com/jauderho/nts-servers/blob/main/chrony.conf), [`ntp.toml`](https://github.com/jauderho/nts-servers/blob/main/ntp.toml), and updates [`README.md`](https://github.com/jauderho/nts-servers/blob/main/README.md) using the conversion logic in `generate_chrony_conf`.

### Updating Stratum Values Automatically

Verify and refresh stratum data without manual editing:

```bash
python3 scripts/ntsUpdateServers.py --dry-run   # Preview changes

python3 scripts/ntsUpdateServers.py            # Apply updates

```

The script loads the YAML via `load_yaml_file`, queries each host through `get_stratum`, and persists changes via `save_yaml_file` (see the `main()` function, lines 90-124).

## Summary

- **[`nts-sources.yml`](https://github.com/jauderho/nts-servers/blob/main/nts-sources.yml)** serves as the single source of truth for NTS server metadata in the `jauderho/nts-servers` repository.
- The YAML schema requires `hostname`, `stratum`, `location`, `owner`, and `vm` fields, with optional `notes`.
- **Alphabetical grouping by country** is mandatory per [`AGENTS.md`](https://github.com/jauderho/nts-servers/blob/main/AGENTS.md) requirements.
- **[`scripts/ntpServerConverter.py`](https://github.com/jauderho/nts-servers/blob/main/scripts/ntpServerConverter.py)** transforms this file into [`chrony.conf`](https://github.com/jauderho/nts-servers/blob/main/chrony.conf), [`ntp.toml`](https://github.com/jauderho/nts-servers/blob/main/ntp.toml), and README documentation.
- **[`scripts/ntsUpdateServers.py`](https://github.com/jauderho/nts-servers/blob/main/scripts/ntsUpdateServers.py)** automates stratum verification and updates against live server data.
- Hostname fields support Markdown link syntax, requiring regex parsing in downstream tools.

## Frequently Asked Questions

### What is the exact structure of the nts-sources.yml file?

The file contains a top-level `servers` key mapped to an ordered list of server entries. Each entry is a YAML mapping with six fields: `hostname` (string, supports Markdown), `stratum` (integer), `location` (string), `owner` (string), `notes` (optional string), and `vm` (boolean). The entire list is organized alphabetically by country to facilitate automated agent workflows.

### How does the repository use nts-sources.yml to generate configs?

The Python script [`scripts/ntpServerConverter.py`](https://github.com/jauderho/nts-servers/blob/main/scripts/ntpServerConverter.py) parses the YAML and invokes specialized generators: `generate_chrony_conf` produces Chrony daemon configurations, `generate_ntp_toml` creates ntpd-rs settings, and `generate_markdown` renders the server table for documentation. All outputs derive from this single YAML source to ensure consistency across the repository.

### Can hostnames in nts-sources.yml contain formatting or URLs?

Yes. The `hostname` field accepts either plain text (e.g., `time.cloudflare.com`) or Markdown hyperlink syntax (e.g., `[time.cloudflare.com](https://time.cloudflare.com)`). Downstream tools like [`scripts/ntsUpdateServers.py`](https://github.com/jauderho/nts-servers/blob/main/scripts/ntsUpdateServers.py) extract the raw hostname using regex patterns to handle both formats correctly during stratum verification.

### How are stratum values in nts-sources.yml kept accurate?

The [`scripts/ntsUpdateServers.py`](https://github.com/jauderho/nts-servers/blob/main/scripts/ntsUpdateServers.py) utility automates this process. It loads the YAML, queries each server using standard NTP tools (`ntpdate`/`ntpq`), and updates the `stratum` field if the live value differs from the stored value. Run with `--dry-run` to preview changes before applying them to the canonical file.