Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Introduction

foton is a font manager for Windows. It installs, updates, and uninstalls fonts for the current user without administrator privileges.

foton can be used in two ways:

  • as a font manager that installs packages from package registries
  • as a tool for users who want to write package manifests or set up custom package registries

This book covers both workflows.

Who this book is for

This book is for anyone who wants to use foton on Windows. It covers both everyday package management tasks and more advanced workflows such as writing package manifests and setting up custom package registries.

Where to start

Windows-only tool

foton is supported on Windows only.

Installing Foton

foton is supported on Windows only.

Install a pre-built binary

Pre-built binaries are published on the GitHub Releases page.

If you already use cargo-binstall, you can install foton with:

cargo binstall foton

If you prefer, you can also download a release archive manually from the Releases page. When installing this way, make sure foton.exe is placed in a directory on your PATH, or add the extraction directory to your PATH yourself.

Install with Cargo

To install foton with Cargo, first install the Rust toolchain. See the Rust installation guide if you do not have Rust yet.

Then install either the latest released version or the current development version from the GitHub repository.

cargo install foton
cargo install --git https://github.com/gifnksm/foton.git foton

Verify the installation

Run:

foton --help

If the command succeeds, foton is installed and available on your PATH.

Next steps

If you are new to foton, read Core Concepts first. Then continue with Basic Usage to learn the everyday workflow for searching, installing, updating, inspecting, and removing packages.

Core Concepts

This chapter introduces a few terms that appear throughout the rest of the book. You do not need to memorize them, but knowing them makes the command and guide pages easier to follow.

Packages

In foton, the main unit of installation is a package. A package is a versioned definition of one or more fonts. When you install, update, list, inspect, or uninstall something with foton, you are working with packages.

Package names and versions

Many commands accept either a package name or a package name with an exact version.

  • <package-name>
  • <package-name>@<version>

Use <package-name> when you want foton to choose an appropriate version for the command you are running. Use <package-name>@<version> when you want to select an exact version.

Package registries

Packages are usually installed from package registries. A package registry is a collection of package definitions that foton can search and install from.

A package registry can be:

  • a local directory on your machine
  • a Git repository that foton fetches and caches locally

The default configuration includes the public foton package registry, which is backed by the gifnksm/foton-registry repository. You can also define your own package registries. See Setting Up Your Own Package Registry for a practical guide. For reference details, see Package Registry Reference and Configuration File Reference.

Manifest files

A manifest file is a TOML file that defines a package. It contains package metadata and one or more downloadable sources from which font files are installed.

Most users will work with packages from package registries. Manifest files become important when you want to:

  • install a package directly from a local manifest file
  • validate a package definition with foton manifest check
  • publish packages through your own package registry

See Writing a Package Manifest for a step-by-step guide and Package Manifest Reference for a field-by-field reference.

Where to go next

Basic Usage

This section covers the everyday workflow for using foton as a font manager.

If terms like package, package registry, or manifest file are unfamiliar, read Core Concepts first.

A typical workflow looks like this:

  1. Discover available packages
  2. Install the packages you want
  3. Update installed packages when newer versions are available
  4. Inspect or remove packages that are already installed

Chapters in this section

If you want to install a package directly from a local manifest file or define your own package registry, continue to Advanced Usage.

Discovering Packages

Use foton search to find packages that are available in your registries.

In the examples below, replace placeholders such as <query> and <registry-id> with real values.

Search for a package by name:

foton search <query>

Search with multiple query terms:

foton search <query-word-1> <query-word-2>

Each query term must match within the same package metadata field. In practice, this means foton can match package names, display names, aliases, face names, and descriptions.

Restrict the search to specific registries

If you want to search only selected package registries, pass --registry with a comma-separated list of package registry IDs.

foton search --registry <registry-id-1>,<registry-id-2> <query>

Control the number of results

By default, foton search shows up to 10 matching packages. Use --limit to change that number.

foton search --limit 20 <query>

Read the results

Search results are printed as package names with versions together with the registry ID that provided the package. If a package has a description, it is shown on the next line.

Example output:

example-font@1.2.3 [example]
  Example font family for UI and coding

By default, search does not include pre-release versions when it selects the latest version of each package in each selected registry. Use --pre-release if you want search results to include pre-release versions. Once you have found a package you want, install it with foton install.

Installing and Updating Packages

This chapter covers the commands you will use most often after discovering a package: install and update.

In the examples below, replace placeholders such as <package-name>, <version>, <registry-id>, and <manifest-path> with real values.

Install packages from package registries

Install a package by name:

foton install <package-name>

Install multiple packages at once:

foton install <package-name-1> <package-name-2>

Install a specific version:

foton install <package-name>@<version>

By default, foton resolves packages from the package registries enabled in your configuration. When resolving a package by name, it does not consider pre-release versions unless you pass --pre-release. To resolve packages only from specific package registries, pass --registry.

foton install --registry <registry-id-1>,<registry-id-2> <package-name>

Install packages from manifest files

install can also install packages defined in local manifest files. This is mainly useful when authoring or testing packages.

foton install --manifest <manifest-path>

You can specify --manifest multiple times. Do not combine --manifest with --registry, --pre-release, or package names.

For more details, see Writing a Package Manifest.

Update installed packages

Update every installed package that has a newer version available:

foton update

Update only selected packages:

foton update <package-name-1> <package-name-2>

You can also select an exact installed version first:

foton update <package-name>@<version>

When you specify an exact version, update selects the matching installed package first, then looks for a newer version of the same package name. By default, update does not look for pre-release versions. Use --pre-release if you want pre-release updates to be considered.

If you want to control which package registries are used to find updates, pass --registry.

foton update --registry <registry-id-1>,<registry-id-2> <package-name>

Confirmation prompts

Commands that change installed packages ask for confirmation before applying changes. If you want to skip the prompt, pass the global --no-confirm option.

foton --no-confirm install <package-name>
foton --no-confirm update

Notes

  • If an install request does not require any changes, foton reports that the package is already installed.
  • If an update request does not require any changes, foton reports that the selected packages are already up to date.
  • If an install or update does not complete cleanly, use foton repair to clean up any packages left behind.
  • Package installation and update operate on package definitions, not on individual font files.

Managing Installed Packages

This chapter covers the commands you use after packages have already been installed: list, info, and uninstall. It also explains how to recover from incomplete operations with repair.

In the examples below, replace placeholders such as <package-name> and <version> with real values.

List installed packages

Show installed packages:

foton list

By default, list shows packages in the installed state.

If you also want to see packages left by incomplete operations, pass --show-incomplete.

foton list --show-incomplete

With --show-incomplete, each entry includes its state, such as installed, incomplete-install, or incomplete-uninstall.

If you see such packages, inspect them with foton info, then clean them up with foton repair. Most of the time, you will work only with installed packages.

Inspect a package in detail

Show detailed information about one or more packages recorded in the local package database:

foton info <package-name>
foton info <package-name>@<version>

info prints the package name, version, state, metadata, and source information for matching packages recorded in the local package database. This can include packages left by incomplete operations. Use this command when you want to confirm exactly what is recorded in the local package database.

Recover from incomplete operations

If list --show-incomplete shows packages left by incomplete operations, use repair to clean them up:

foton repair

You can also target a specific package:

foton repair <package-name>
foton repair <package-name>@<version>

repair cleans up those packages. It does not resume an interrupted install or update.

Remove a package

Uninstall one or more packages:

foton uninstall <package-name>
foton uninstall <package-name-1> <package-name-2>

Like install and update, uninstall asks for confirmation before applying changes. If an uninstall does not complete cleanly, use foton repair to clean up any packages it leaves behind. If you want to skip the prompt, pass the global --no-confirm option.

foton --no-confirm uninstall <package-name>

Typical workflow

A common workflow is:

  1. Run foton list to see what is installed
  2. Run foton info <package-name> to inspect a package in detail
  3. Run foton uninstall <package-name> to remove a package you no longer need

Advanced Usage

This section is for users who want to do more than install packages from the public package registry.

Typical advanced workflows include:

  • writing your own package manifest
  • validating that manifest before publishing or installing it
  • testing a manifest locally with foton install --manifest
  • setting up a custom package registry
  • using local and Git-backed package registries from your configuration

Suggested workflow

If you are creating a package, a typical workflow looks like this:

  1. Write a package manifest
  2. Run foton manifest check to validate it
  3. Test it locally with foton install --manifest
  4. Add it to a package registry if you want to distribute it

Chapters in this section

Writing a Package Manifest

A package manifest is a TOML file that defines a font package. It tells foton what the package is called, where its downloadable sources are, and which files from those sources should be installed as fonts.

Typical workflow

A practical workflow for authoring a package is:

  1. Write a manifest file
  2. Run foton manifest check on it
  3. Install it locally with foton install --manifest
  4. Add it to a package registry if you want to publish it

Example manifest

name = "example-font"
display-name = "Example Font"
version = "1.2.3"
description = "Example font family for UI and coding"
aliases = [
  "Example Font UI",
  "Example Font Console",
]
faces = [
  "Example Font Regular",
  "Example Font Bold",
  "Example Font UI Regular",
  "Example Font UI Bold",
]
homepage = "https://example.com/example-font"
repository = "https://github.com/example/example-font"
license = "OFL-1.1"

[[sources]]
url = "https://example.com/downloads/example-font-1.2.3.zip"
hash = "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
include = [
  "example-font-1.2.3/ExampleFont-Regular.ttf",
  "example-font-1.2.3/ExampleFont-Bold.ttf",
  "example-font-1.2.3/ExampleFontUI-Regular.ttf",
  "example-font-1.2.3/ExampleFontUI-Bold.ttf",
]

Required fields

This section is a quick checklist, not a complete field reference. See Package Manifest Reference for a detailed description of every field.

At minimum, a manifest must define:

  • name
  • version
  • sources

Each sources entry must define:

  • url
  • hash

Choosing a package version

Choose a version that identifies one specific immutable release and sorts in release order for that package.

A practical way to choose package versions is:

  • Use the upstream release version when it already fits foton’s package-version format.
  • If there is no usable upstream version, use a calendar-based version such as 2024.05.11.
  • If you need to publish a pre-release, add a suffix to the final part. A suffix marks the version as a pre-release and sorts it before the corresponding version without a suffix, such as 1.4.0-rc-1 < 1.4.0 or 2024.05.11-beta-2 < 2024.05.11.
  • If the upstream version does not fit foton’s package-version syntax, rewrite it in a form that still preserves the upstream release ordering and whether the release is stable or pre-release. For example, rewrite v1.4.0 as 1.4.0, and rewrite 1.4.0-rc10 as 1.4.0-rc-10.
  • Keep the notation consistent within the same package to avoid non-intuitive ordering results:
    • Do not mix forms such as 2024.5.11 and 2024.05.11, because they are different versions.
    • Keep the same number of numeric parts within a package. For example, prefer a consistent series such as 1.2.0, 1.3.0, and 1.4.0-rc-1 over mixing forms such as 1.2, 1.3.0, and 1.4-rc-1.

For the exact package-version syntax and ordering rules, see Package Manifest Reference.

These fields are optional, but they are strongly recommended because they help users discover and understand the fonts provided by the package. See Package Manifest Reference for the complete field definitions and constraints.

These fields are recommended:

  • display-name
  • description
  • license
  • aliases
  • faces
  • homepage
  • repository

These metadata fields describe the fonts provided by the package, not the package definition itself. In particular, homepage, repository, and license should refer to the upstream font project or the upstream font files included in the package.

If there is no suitable upstream homepage or repository, omit that field. Do not repeat repository in homepage just to fill both fields.

foton manifest check warns if display-name, description, or license is missing.

Choosing files from a source

Each sources[] entry can define sources[].include and sources[].exclude patterns. Use them to control which files from the downloaded archive or file are treated as installable fonts. See Package Manifest Reference for the exact behavior of sources, sources[].include, and sources[].exclude.

If you omit sources[].include, foton uses these default patterns:

  • **/*.ttf
  • **/*.otf
  • **/*.ttc

Prefer sources[].include entries that list each font file path explicitly. Avoid wildcard patterns when possible. This makes it clear from the manifest exactly which files belong to the package, and it reduces the chance of unintentionally picking up extra or unexpected files from the source archive.

If the source archive contains other font-like files such as *.ttf, *.otf, or *.ttc that you do not want to install, prefer listing those paths in sources[].exclude explicitly. That makes the omission visible in the manifest and shows that the files were left out intentionally.

Validate the manifest

Run:

foton manifest check <manifest-path>

manifest check does more than syntax validation. It reads the manifest, stages the package, downloads the sources, and verifies that installation would succeed. It can also warn about issues such as:

  • missing display-name, description, or license
  • duplicated display names or face names
  • wildcard include patterns that are broader than necessary
  • include or exclude patterns that match nothing
  • font-like files that match neither include nor exclude

If you want warnings to fail the command, use the global --warnings-as-errors option.

foton --warnings-as-errors manifest check <manifest-path>

Test the manifest locally

You can install a package directly from a local manifest file:

foton install --manifest <manifest-path>

This is useful before publishing the manifest in a registry. It lets you test the actual install workflow with the same manifest content.

Publish through a registry

Once a manifest works locally, place it in a package registry so it can be resolved by package name. See Setting Up Your Own Package Registry.

Setting Up Your Own Package Registry

A package registry is a collection of package manifests that foton can search and install from. You can use your own package registry to distribute internal packages, test packages before publishing them elsewhere, or maintain a curated set of fonts.

This chapter focuses on the setup workflow. For the exact registry layout and configuration format, see Package Registry Reference and Configuration File Reference.

Registry types

foton supports two kinds of package registry sources:

  • local+<absolute-path> for a registry stored in a local directory
  • git+<url> for a registry stored in a Git repository

The default configuration already includes the public foton package registry. Custom package registries are added through your config.toml file.

Registry layout

A registry stores package manifests in this directory layout:

<registry-root>/
  <package-name>/
    <version>/
      manifest.toml

Example:

my-registry/
  example-font/
    1.2.3/
      manifest.toml
  another-font/
    2.0.0/
      manifest.toml

Each package version has its own manifest.toml file. This layout lets a single registry contain multiple versions of the same package.

Add a local registry

A local registry path must be absolute. Add an entry to your config.toml file:

[registries.example]
source = "local+C:/path/to/my-registry"
enabled = true

After that, you can search or install from that package registry by ID:

foton search --registry example <query>
foton install --registry example <package-name>

Add a Git registry

To use a registry from Git, add a git+ source to your config.toml file:

[registries.example]
source = "git+https://example.com/fonts/example-registry.git"
enabled = true

Then use it the same way:

foton search --registry example <query>
foton install --registry example <package-name>

foton caches Git registries locally and updates the cached repository when it fetches registry contents.

Enable or disable a registry

Each registry entry has an enabled flag. If omitted, it defaults to true. Set it to false when you want to keep the registry definition in your config.toml file without using it by default. You can still opt in to a disabled package registry explicitly with --registry <registry-id>. If all configured package registries are disabled, commands such as search, install, and update fail unless you specify --registry.

[registries.example]
source = "local+C:/path/to/experimental-registry"
enabled = false

Publish your own packages

A common workflow is:

  1. Write and validate a manifest locally
  2. Place the manifest at <package-name>/<version>/manifest.toml in your registry
  3. Add the registry to your config.toml file
  4. Search or install from that package registry with --registry <registry-id>

If you enable multiple package registries that contain the same package name, install and update may ask you to disambiguate by narrowing --registry.

Package Manifest Reference

A package manifest is a TOML document that defines a single package version. It is used both for packages stored in registries and for local manifest files installed with foton install --manifest.

Format overview

A manifest uses kebab-case field names. Unknown fields are rejected.

At the top level, a manifest contains package metadata and a non-empty sources array.

Example

name = "example-font"
display-name = "Example Font"
version = "1.2.3"
description = "Example font family for UI and coding"
aliases = [
  "Example Font UI",
  "Example Font Console",
]
faces = [
  "Example Font Regular",
  "Example Font Bold",
  "Example Font UI Regular",
  "Example Font UI Bold",
]
homepage = "https://example.com/example-font"
repository = "https://github.com/example/example-font"
license = "OFL-1.1"

[[sources]]
url = "https://example.com/downloads/example-font-1.2.3.zip"
hash = "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
include = [
  "example-font-1.2.3/ExampleFont-Regular.ttf",
  "example-font-1.2.3/ExampleFont-Bold.ttf",
]

Validation and quality checks

Use foton manifest check to validate a manifest. The command checks both installation errors and quality issues. For example, it can report:

  • missing recommended fields such as display-name, description, or license
  • duplicate display names or face names after normalization
  • include or exclude patterns that match nothing
  • wildcard include patterns that are broader than necessary
  • font-like files in a source that are neither included nor excluded

Package version format and ordering

In a package manifest, the version field uses foton’s package-version format. It identifies a single immutable package release and is also used to order package versions when foton selects newer or older releases.

Format

A package version follows this grammar:

<package-version> = <numeric-part> ("." <numeric-part>)* [<suffix>]
<suffix> = "-" <alpha-identifier> ("-" <suffix-identifier>)*
<numeric-part> = <digit>+
<alpha-identifier> = <lowercase-letter>+
<suffix-identifier> = <alpha-identifier> | <digit>+
<digit> = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"
<lowercase-letter> = "a" | ... | "z"

Additional rules:

  • <suffix> may appear only after the final <numeric-part>
  • <suffix> denotes a pre-release of the same <package-version> without the <suffix>
  • <suffix-identifier> values are written as separate --delimited tokens, so use 1.0.0-rc-10, not 1.0.0-rc10

Valid examples:

  • 2407.24
  • 2024.05.11
  • 1.2.3
  • 1.0.0-rc-1

Invalid examples:

  • 1-rc.10
  • 1.0-beta.2
  • 1-rc10
  • 1-RC

Comparison rules

Versions are compared in this order:

  1. Compare corresponding <numeric-part> values from left to right.
  2. Compare each <numeric-part> by numeric value.
  3. If two <numeric-part> values have the same numeric value, the one with fewer leading zeros is older.
  4. If all shared <numeric-part> values are equal and one <package-version> has fewer <numeric-part> values, the shorter version is older.
  5. A <package-version> with a <suffix> is a pre-release and is older than the same <package-version> without a <suffix>.
  6. If both versions have <suffix> values, compare corresponding <suffix-identifier> values from left to right.
  7. Numeric <suffix-identifier> values are compared by numeric value and are older than alphabetic <suffix-identifier> values.
  8. If two numeric <suffix-identifier> values have the same numeric value, the one with fewer leading zeros is older.
  9. If all shared <suffix-identifier> values are equal and one <suffix> has fewer identifiers, the shorter suffix is older.

Comparison examples

  • Numeric parts are compared from left to right:
    • 1.2.0 < 1.10.0
    • 1.2 < 1.2.0
    • 1 < 1.0-rc < 1.0
  • Leading zeros affect ordering when the numeric values are otherwise equal:
    • 5 < 05 < 005
    • 2024.5.11 < 2024.05.11
  • A suffix makes a version older than the same version without a suffix:
    • 1.0.0-rc < 1.0.0
    • 2024.05.11-beta-2 < 2024.05.11
  • Suffix identifiers are compared from left to right:
    • 1.0.0-alpha < 1.0.0-beta
    • 1.0.0-rc-2 < 1.0.0-rc-10
    • 1.0.0-rc-1 < 1.0.0-rc-a
    • 1.0.0-rc < 1.0.0-rc-1

Top-level fields

Field headings indicate whether a field is required or optional. Fields marked recommended are optional, but strongly recommended because they help users discover and understand the fonts provided by the package. Metadata fields such as display-name, description, aliases, faces, homepage, repository, and license describe the fonts provided by the package. Packaging fields such as name, version, and sources describe how foton identifies and installs the package.

name (required)

The canonical package name used in commands such as foton install <package-name>. This is the stable identifier for the package.

  • Type: package name string

  • Constraints: must start with an ASCII letter and contain only ASCII letters, digits, -, or _

  • Example:

    name = "example-font"
    

A human-friendly primary name for the font family, collection, or bundle provided by the package. Use this for the primary label shown to users in search results and other output.

  • Type: string

  • Constraints: must be non-empty and must not have leading or trailing whitespace

  • Recommended because: it gives users a clear primary name for the fonts provided by the package

  • Example:

    display-name = "Example Font"
    

version (required)

The package version. Use a version string that identifies an immutable package release.

  • Type: package version string

  • Constraints: must follow the package-version format described above

  • Example:

    version = "1.2.3"
    

A short description of the font family, collection, or bundle provided by the package.

  • Type: string

  • Constraints: must be non-empty and must not have leading or trailing whitespace

  • Recommended because: it appears in search results and package details

  • Example:

    description = "Example font family for UI and coding"
    

Alternative names and spellings for the font family, collection, or bundle used for search. Use this for family or collection names, abbreviations, and alternate spellings.

  • Type: array of strings

  • Constraints: each entry must be non-empty and must not have leading or trailing whitespace

  • Recommended because: it helps users find the package by alternate names and spellings

  • Example:

    aliases = ["Example Font UI", "Example Font Console"]
    

Human-friendly names for the individual font faces included in the package. Use this for entries such as Regular, Bold, or other specific face names.

  • Type: array of strings

  • Constraints: each entry must be non-empty and must not have leading or trailing whitespace

  • Recommended because: it helps users find the package by included face names

  • Example:

    faces = ["Example Font Regular", "Example Font Bold"]
    

The upstream homepage for the font project or distribution represented by the package.

  • Type: URL string

  • Constraints: the URL scheme must be http or https; omit this field if there is no distinct upstream homepage

  • Recommended because: it gives users a homepage for more information about the fonts provided by the package

  • Note: do not duplicate repository here when both would be the same URL

  • Example:

    homepage = "https://example.com/example-font"
    

The upstream source repository for the font project represented by the package.

  • Type: URL string

  • Constraints: the URL scheme must be http or https; omit this field if there is no suitable public upstream repository

  • Recommended because: it gives users a source repository for the upstream font project

  • Example:

    repository = "https://github.com/example/example-font"
    

The SPDX license expression for the upstream font files included in the package.

  • Type: SPDX expression string

  • Constraints: must be a valid SPDX expression

  • Recommended because: it tells users the licensing terms of the font files included in the package

  • Example:

    license = "OFL-1.1"
    

sources (required)

A non-empty array of source objects. Each source describes one downloadable archive or file from which foton can install fonts.

  • Type: non-empty array of source objects

  • Example:

    [[sources]]
    url = "https://example.com/downloads/example-font-1.2.3.zip"
    hash = "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
    

Source fields

Field headings indicate whether a field is required or optional. Each entry in sources supports the following fields.

sources[].url (required)

The downloadable archive or file that contains the package contents.

  • Type: URL string

  • Constraints: the URL scheme must be http or https

  • Example:

    [[sources]]
    url = "https://example.com/downloads/example-font-1.2.3.zip"
    

sources[].hash (required)

The expected digest used to verify source integrity.

  • Type: digest string

  • Constraints: must include an algorithm prefix such as sha256:; currently sha256 is supported

  • Example:

    [[sources]]
    hash = "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
    

Glob patterns that select font files from the downloaded source. If omitted, foton uses the default font-file patterns.

  • Type: array of glob patterns

  • Constraints: must be non-empty if present

  • Default: **/*.ttf, **/*.otf, and **/*.ttc

  • Recommended because: it makes the package contents explicit and reduces unintended matches from the source archive

  • Example:

    [[sources]]
    include = [
      "fonts/ExampleFont-Regular.ttf",
      "fonts/ExampleFont-Bold.ttf",
    ]
    

sources[].exclude (optional)

Glob patterns that exclude files even if they match include. If a path matches both include and exclude, exclude takes precedence.

  • Type: array of glob patterns

  • Example:

    [[sources]]
    exclude = [
      "fonts/Extra.ttf",
    ]
    

Package Registry Reference

A package registry is a collection of package manifests that foton can search and install from. A registry may be stored in a local directory or in a Git repository.

Directory layout

A registry is organized by package name and package version:

<registry-root>/
  <package-name>/
    <version>/
      manifest.toml

Example:

registry/
  example-font/
    1.2.3/
      manifest.toml
  another-font/
    2.0.0/
      manifest.toml

The package ID in the manifest must match the directory that contains it. In other words, the manifest at example-font/1.2.3/manifest.toml must describe example-font@1.2.3.

When foton scans the registry layout:

  • under <registry-root>, only directories are considered package-name entries; hidden entries and other non-directory entries are ignored
  • under each <package-name> directory, only directories are considered version entries; hidden entries and other non-directory entries are ignored
  • within each <version> directory, foton reads manifest.toml; other files are ignored for package discovery

Registry configuration

Registries are configured in your config.toml file under [registries.<registry-id>]. <registry-id> is a user-defined identifier such as foton, local, or team. Commands that support --registry use these registry IDs, not paths or URLs.

Each registry entry specifies a source. foton currently supports these source formats:

  • local+<absolute-path>
  • git+<url>

A local+... source points directly at a directory on your machine. A git+... source points at a Git repository URL and is fetched into a local cache before use.

Example:

[registries.example]
source = "local+C:/path/to/my-registry"
enabled = true
foton search --registry example <query>

For the exact configuration format, see Configuration File Reference.

Configuration File Reference

foton loads configuration from a config.toml file in its configuration directory. If the file does not exist, built-in defaults are used.

On Windows, the configuration file is stored at:

%APPDATA%\io.github.gifnksm\foton\config\config.toml

What configuration controls

The configuration file currently controls:

  • install-time safety limits for downloaded archives and extracted files
  • the set of configured package registries
  • whether each configured registry is enabled by default

Default behavior and merge rules

config.toml is optional. If it is present, foton merges it onto built-in defaults.

This means:

  • omitted sections and keys keep their default values
  • unknown keys are rejected
  • the default configuration already includes the public foton package registry

Example configuration

[install]
max-archive-size-bytes = 536870912
max-extracted-files = 1000
max-extracted-file-size-bytes = 52428800

[registries.foton]
source = "git+https://github.com/gifnksm/foton-registry.git"
enabled = true

[registries.local]
source = "local+C:/path/to/my-registry"
enabled = true

[registries.experimental]
source = "git+https://example.com/fonts/experimental-registry.git"
enabled = false

Top-level sections

Field headings indicate whether a section or key is optional. Defaults are listed in the metadata bullets for the relevant sections and keys.

install (optional)

The install section defines safety limits used while processing package sources.

  • Type: table

  • Default: built-in install limits are used if this section is omitted

  • Example:

    [install]
    max-archive-size-bytes = 536870912
    max-extracted-files = 1000
    max-extracted-file-size-bytes = 52428800
    

registries (optional)

The registries table contains registries.<registry-id> entries keyed by registry ID. Each registries.<registry-id> entry configures one registry that foton can search or install from.

  • Type: table of registry entries

  • Default: the built-in registries.foton entry is present even if this section is omitted

  • Example:

    [registries.example]
    source = "local+C:/path/to/my-registry"
    enabled = true
    

Install section fields

install.max-archive-size-bytes (optional)

The maximum allowed size, in bytes, of a downloaded archive or source file.

  • Type: unsigned integer

  • Default: 536870912 (512MiB)

  • Example:

    [install]
    max-archive-size-bytes = 536870912
    

install.max-extracted-files (optional)

The maximum number of files that may be extracted from a source archive.

  • Type: unsigned integer

  • Default: 1000

  • Example:

    [install]
    max-extracted-files = 1000
    

install.max-extracted-file-size-bytes (optional)

The maximum allowed size, in bytes, of a single extracted file.

  • Type: unsigned integer

  • Default: 52428800 (50MiB)

  • Example:

    [install]
    max-extracted-file-size-bytes = 52428800
    

Registry entry fields

registries.<registry-id> (optional)

A single registry entry. <registry-id> is a user-defined registry ID. Commands such as foton search --registry ... and foton install --registry ... use these registry IDs.

  • Type: table

  • Constraints: the registry ID must start with an ASCII letter and contain only ASCII letters, digits, -, or _

  • Example:

    [registries.example]
    source = "local+C:/path/to/my-registry"
    enabled = true
    

registries.<registry-id>.source (required)

The source from which foton loads the registry. Use local+... for a local directory or git+... for a Git-backed registry.

  • Type: registry source string

  • Constraints: must be either local+<absolute-path> or git+<url>

  • Example:

    [registries.example]
    source = "local+C:/path/to/my-registry"
    
    [registries.example]
    source = "git+https://example.com/fonts/example-registry.git"
    

registries.<registry-id>.enabled (optional)

Whether the registry is enabled by default. Set this to false when you want to keep the registry configured but not use it unless you opt in explicitly.

If you pass --registry <REGISTRY_ID>, foton can still use that package registry even when enabled = false. If all configured package registries are disabled and you do not pass --registry, commands such as search, install, and update fail because there are no enabled package registries to use.

  • Type: boolean

  • Default: true

  • Example:

    [registries.example]
    enabled = false
    

Command Reference

This section documents the foton command-line interface.

Command structure

The general command format is:

foton [GLOBAL_OPTIONS] <COMMAND> [COMMAND_OPTIONS] [ARGS...]

Run foton --help to see the complete command-line help.

Global options

--no-confirm

Skip interactive confirmation prompts. This is most useful with commands that change installed packages, such as install, update, and uninstall.

--warnings-as-errors

Treat warnings as errors, causing the command to fail if any warning is emitted.

Commands

install

Install packages from package registries or manifest files.

Usage

Install from package registries:

foton install [OPTIONS] [<PACKAGE>...]

Install from local manifest files:

foton install [OPTIONS] --manifest <MANIFEST>...

Arguments

<PACKAGE>

Package names, optionally with an exact version as <package-name>@<version>.

Required unless --manifest is specified. This cannot be used together with --manifest.

Options

--manifest <MANIFEST>

Install packages defined in the given manifest files.

This option can be specified multiple times. It cannot be used together with --registry, --pre-release or <PACKAGE>.

--registry <REGISTRY_ID>

Package registry IDs to resolve packages from.

Use a comma-separated list such as --registry local,foton. This option is only available when installing by <PACKAGE>.

--no-confirm

Skip interactive confirmation prompts.

--warnings-as-errors

Treat warnings as errors, causing the command to fail if any warning is emitted.

--pre-release

Allow installing pre-release versions when resolving packages from registries.

Without this option, versions with a suffix such as 1.2.3-rc-1 are ignored unless an exact version is specified. This cannot be used together with --manifest.

Examples

foton install <package-name>
foton install <package-name>@<version>
foton install --registry <registry-id-1>,<registry-id-2> <package-name>
foton install --manifest <manifest-path>

Notes

  • If the selected packages are already installed and nothing needs to change, foton reports that and exits without modifying the system.
  • When installing by package name, if a matching package is already installed locally, foton keeps that installed package as the selected result. Use foton update when you want to look for newer versions in package registries.
  • If an install does not complete cleanly, use repair to clean up any packages it leaves behind.
  • If multiple selected package registries provide a matching package, install does not choose one automatically; it fails and asks you to disambiguate.
  • Installing from a manifest file is useful for local testing before adding it to a package registry.

update

Update installed packages from package registries.

Usage

foton update [OPTIONS] [<PACKAGE>...]

Arguments

<PACKAGE>

Package names, optionally with an exact version as <package-name>@<version>.

If not specified, all installed packages will be updated if possible. When an exact version is specified, update selects the matching installed package first, then looks for a newer version of the same package name.

Options

--registry <REGISTRY_ID>

Package registry IDs to resolve packages from.

Use a comma-separated list such as --registry local,foton.

--no-confirm

Skip interactive confirmation prompts.

--warnings-as-errors

Treat warnings as errors, causing the command to fail if any warning is emitted.

--pre-release

Allow updating to pre-release versions when resolving packages from registries.

Without this option, versions with a suffix such as 1.2.3-rc-1 are ignored.

Examples

foton update
foton update <package-name>
foton update --registry <registry-id-1>,<registry-id-2> <package-name>

Notes

  • If no newer version is available for the selected packages, foton reports that they are already up to date.
  • If an update does not complete cleanly, use repair to clean up any packages it leaves behind.
  • Update resolution uses package names and package registry IDs, not manifest files.
  • If multiple selected package registries provide newer versions of the same package, update does not choose one automatically; it fails and asks you to disambiguate.

uninstall

Uninstall packages recorded in the local package database.

Usage

foton uninstall [OPTIONS] <PACKAGE>...

Arguments

<PACKAGE>

Package names, optionally with an exact version as <package-name>@<version>.

Options

--no-confirm

Skip interactive confirmation prompts.

--warnings-as-errors

Treat warnings as errors, causing the command to fail if any warning is emitted.

Examples

foton uninstall <package-name>
foton uninstall <package-name-1> <package-name-2>

Notes

  • If the selected package is already absent, foton reports that there is nothing to do.
  • If an uninstall does not complete cleanly, use repair to clean up any packages it leaves behind.
  • uninstall operates on packages recorded in the local package database and does not access package registries.

repair

Clean up packages in the local package database that were left by incomplete installs, uninstalls, or updates.

Installed packages are not changed by repair. repair only performs cleanup; it does not resume an interrupted install or update.

Usage

foton repair [OPTIONS] [<PACKAGE>...]

Arguments

<PACKAGE>

Package names, optionally with an exact version as <package-name>@<version>.

If not specified, every package that needs cleanup will be cleaned up.

Options

--no-confirm

Skip interactive confirmation prompts

--warnings-as-errors

Treat warnings as errors, causing the command to fail if any warning is emitted

Examples

foton repair
foton repair <package-name>
foton repair <package-name>@<version>

Notes

  • Installed packages are not changed by repair.
  • If a selected package is already in a consistent state, foton reports that there is nothing to do.
  • If cleanup cannot be completed, the package may remain in the local package database so that you can retry repair later.

list

List installed packages.

Usage

foton list [OPTIONS]

Options

--show-incomplete

Include packages left by incomplete installs, uninstalls, or updates.

Without this option, only packages in the installed state are shown. With this option, leftover packages are shown with states such as incomplete-install and incomplete-uninstall.

--no-confirm

Skip interactive confirmation prompts.

--warnings-as-errors

Treat warnings as errors, causing the command to fail if any warning is emitted.

Examples

Show installed packages:

foton list

Show installed packages together with leftover packages from incomplete installs, uninstalls, or updates, and their states:

foton list --show-incomplete

Output

Without --show-incomplete, each line contains a package name and version:

example-font@1.2.3

With --show-incomplete, each line also includes the package state:

example-font@1.2.3 (installed)
another-font@0.1.0 (incomplete-install)

Notes

  • list reads the local package database and does not access package registries.
  • Use info when you want more than the package name, version, and state.

info

Show detailed information about packages recorded in the local package database.

Usage

foton info [OPTIONS] <PACKAGE>...

Arguments

<PACKAGE>

Package names, optionally with an exact version as <package-name>@<version>.

Options

--no-confirm

Skip interactive confirmation prompts.

--warnings-as-errors

Treat warnings as errors, causing the command to fail if any warning is emitted.

Examples

foton info <package-name>
foton info <package-name>@<version>

Output

info prints detailed metadata for matching packages recorded in the local package database, including:

  • package name and display name
  • version and current package state
  • description, aliases, faces, homepage, repository, and license
  • source URLs, hashes, and include or exclude patterns

If a package name matches multiple packages recorded in the local package database, info prints all of them. This can include packages left by incomplete operations.

Notes

  • info reads the local package database and does not search package registries.
  • If no package recorded in the local package database matches the specified package name, the command fails.
  • Use repair when you want to clean up packages left by incomplete operations.
  • Use search when you want to inspect packages that are available in a package registry but not yet installed.

search

Search packages in package registries.

Usage

foton search [OPTIONS] <QUERY>...

Arguments

<QUERY>

Search query terms.

All specified query terms must match within the same package metadata field.

Options

--registry <REGISTRY_ID>

Package registry IDs to search.

Use a comma-separated list such as --registry local,foton.

--limit <LIMIT>

Maximum number of matching packages to show.

--no-confirm

Skip interactive confirmation prompts.

--warnings-as-errors

Treat warnings as errors, causing the command to fail if any warning is emitted.

--pre-release

Allow matching pre-release versions when searching packages in registries.

Without this option, versions with a suffix such as 1.2.3-rc-1 are ignored.

Examples

foton search <query>
foton search --limit 20 <query>
foton search --registry <registry-id-1>,<registry-id-2> <query>

Output

Each result shows the package name with version and the package registry ID in brackets. If the package has a description, it is printed on the next line.

Example:

example-font@1.2.3 [example]
  Example font family for UI and coding

Notes

  • By default, search looks at the latest version of each package in each selected package registry without considering pre-release versions. Use --pre-release if you want pre-release versions to be included.
  • Search can match package names, display names, aliases, faces, and descriptions.
  • If no matching packages are found, the command fails.

manifest

Work with package manifest files.

Usage

foton manifest <COMMAND>

Commands

  • check: validate a manifest file for installation errors and quality warnings

Typical usage

The manifest command group is mainly intended for package authors. A common workflow is:

  1. Write a manifest file
  2. Run foton manifest check <MANIFEST>
  3. Install the manifest locally with foton install --manifest <MANIFEST>
  4. Add the manifest to a package registry

manifest check

Validate a manifest file for installation errors and quality warnings.

Usage

foton manifest check [OPTIONS] <MANIFEST>

Arguments

<MANIFEST>

Path to the manifest file to validate.

Options

--no-confirm

Skip interactive confirmation prompts.

--warnings-as-errors

Treat warnings as errors, causing the command to fail if any warning is emitted.

What the command checks

manifest check reads the manifest and then stages it as if it were going to be installed. This includes downloading and examining the source archives or files described by the manifest.

The command reports:

  • installation errors that would prevent the package from being installed
  • quality warnings for common authoring mistakes

Common warnings

Warnings can include:

  • missing display-name
  • missing description
  • missing license
  • duplicate display names or face names after normalization
  • include patterns that match nothing
  • exclude patterns that match nothing
  • wildcard include patterns that are broader than necessary
  • font-like files that are neither included nor excluded

Examples

foton manifest check <manifest-path>

Treat warnings as errors:

foton --warnings-as-errors manifest check <manifest-path>

Notes

  • This command is primarily intended for package authors.
  • Because the command fetches sources, network access may be required.
  • A manifest that parses successfully can still fail manifest check if the sources are invalid or the selected files do not install correctly.