Accent CMS 0.28: stable page identity, computed values, and pages from other sites

Accent CMS 0.28.0 is available. Three changes can have an effect on your site when you upgrade. Read these changes first.

Before you upgrade

accent build and accent serve select the same index file. A directory can contain more than one index file. In this condition, accent build now uses the documented priority: default.md, then README.md, then index.md. accent serve always used this priority. Before this release, accent build used the last file in sort order. As a result, index.md replaced README.md and default.md. If your built site uses the old result, keep only one index file in each directory.

URL paths in aliases are redirects. The aliases list in the frontmatter of a page can contain a URL path, for example /old-url. On all sites, the page now answers at this path:

  • accent serve redirects the path to the page.
  • accent build writes a redirect stub at the path.

If a different page is already at the path, Accent does not change that page. If you use the aliases key for a different purpose, change the name of the key.

accent validate checks page identity. Two pages with the same uid are now an error on all sites. A type: reference field with a model: value now resolves its value to a page. If the value does not identify a page of that model, accent validate shows an error. A site that does not use these two functions has no new findings.

Stable page identity

When you move or rename a page, the URL of the page changes. The identity of the page does not change. A model that declares uid: and alias: gives each page two values:

  • A uid. Accent makes the uid one time, when you create the page.
  • An optional alias. The alias is the label that people use for the page, for example d042.
# models/decision.yaml
uid:
  required: true
alias:
  grammar: "d{number}"
  scope: global
  renumber: retire
fields:
  supersedes:
    type: reference
    model: decision
  • accent new, the admin editor, the content API, agents, and MCP make the uid. You do not write the uid manually.
  • With renumber: retire, a page that receives a new alias keeps the old alias in an aliases list. Accent keeps the claim on the old alias, and the old alias resolves to the page. Because of this, references to the old alias continue to work.
  • With renumber: never, a page cannot receive a new alias.
  • A type: reference field with a model: value contains an alias, a retired alias, or a uid. Accent resolves the value to the page.
  • accent validate shows a reference that resolves to no page or to a page of the wrong model.
  • In a template, identity_index() gives the page URL for each uid, alias, and retired alias.
  • With allocation: ref, a model claims each new alias on the shared Git remote. Two writers cannot claim the same alias. The remote rejects the second push, and the second writer receives the next alias. This function needs an origin remote and a network connection when you create the page.

Moved pages keep their URLs

A model can declare alias: { grammar: path }. Then the URL of the page is its alias. You can move this type of page in the admin, on the CLI, or through the API. When you move the page, Accent adds the old URL to aliases:

  • accent serve redirects the old URL to the page.
  • accent build writes a redirect stub at the old URL.

Because of this, a static host needs no more rules.

Computed values

A model can declare values that all pages of the model have. Accent calculates the values when it renders a page. Accent does not store the values.

# models/epic.yaml
computed:
  features_total: { query: count, from: feature, via: epic }
  features_done:  { query: count, from: feature, via: epic, where: { state: done } }
  budget:         { query: sum, from: feature, via: epic, field: price }
  remaining:      { formula: "features_total - features_done" }

There are two types of computed value:

  • A query counts (count), adds (sum), or groups (group) the pages of a different model. The via key identifies the field that connects the pages. A sum gives an exact decimal string.
  • A formula uses the fields of the page and the other computed values of the page. A formula can use arithmetic, comparisons, and, or, not, and the date and decimal functions.

You can read computed values in these locations:

  • In a template: use page.computed, for example {{ page.computed.features_done | default(0) }}.
  • In a page body: use the $computed variables, for example {% $computed.features_done %}. You can use a value in an {% if %} tag. You do not have to change the template.
  • On the command line: accent query computed <url> shows the computed values of a page as JSON.
  • In the REST API: when api.enabled is on, GET /api/v1/computed/<url> gives the values.
  • In MCP and agents: the MCP server and accent agent sessions have a get_computed tool. In agent sessions, the tool is read-only.
  • In static output: accent build writes /api/v1/computed/<url>.json for each page that has values. Because of this, a CDN that serves the built output gives the same answer as the server.

accent validate shows these errors:

  • A query or a formula that fails.
  • A formula cycle.
  • A $computed name that the model of the page does not declare.

When the computed values of a cached page change, the server renders the page again.

Import pages from other sites

The accent content import command copies the pages of a different site into your site:

accent content import ../accent-sass

The command copies each markdown page of the source to content/imports/<origin>/. Each copy keeps its uid and its relative path. Each copy also has origin: <slug> in its frontmatter. Accent uses the slug from the --origin option or from the site.origin value of the source site.

When you import again, Accent replaces pages by uid. Because of this, if the source site moved a page, the new copy replaces the old copy. To see the changes before Accent makes them, use the --dry-run option.

A site sets its own name with site.origin in config.yaml. Imported pages keep their aliases in their own origin. Because of this, your page f12 and an imported page f12 can both exist:

  • To refer to the imported page, write dep: accent-sass/f12.
  • An alias without an origin always identifies a page of your site.
  • In an imported page, an alias without an origin identifies a page of the source site.

accent validate shows a warning if a reference with an origin identifies a page that you did not import. A computed group query on the origin field counts the pages from each source.

Select your index file names

A file with the name default.md, README.md, or index.md gives the content for the URL of its directory. To change this list, set content.index_files in config.yaml:

content:
  index_files: [default.md, README.md, index.md, Home.md]

You can add a name, for example Home.md (the GitHub wiki convention). You can also change the priority or remove a name.

To use a different list in one part of the content tree, set index_files in a _model.yaml file in that directory. The list applies to that directory and to all directories below it. Accent always uses default.md as an index file.

Other fixes

  • After you change the license key and reload the configuration, accent serve --production now sends the new X-Accent-License value. Before this release, the server sent the old value until it restarted.
  • accent new now numbers pages correctly in a flat directory. Before, a {number} or {order} token in the file name pattern always gave 0 or 01. Now, accent new uses the number after the highest number in the target directory.
  • If the file pattern of a model is different for each page, accent new now writes the file directly into --path.
  • If --path does not exist, accent new now shows an error. Before, the command made a new directory tree.
  • An incremental accent build now updates computed values. Before, a page that showed a count kept the old number until a clean build.
  • uid, alias, aliases, and origin are now core fields. Strict mode does not show them as unknown fields. The admin shows them as read-only fields.
  • accent init --docs now adds a Topics page to each version of the docs site. The command also makes a models/ directory with a model that shows computed values.

Other changes

Accent no longer contains the rsa crate. cargo audit reported a problem in this crate, but Accent did not use the crate. Your license keys continue to work. Approximately 110 dependencies now use their latest compatible releases. Diagrams look the same as before.

The GitHub release has the full list of changes.

To install or upgrade, run this command:

curl -fsSL https://accentcms.dev/install.sh | sh

The GitHub release page has the binaries for all platforms, the checksums, and the signatures.