> For the complete documentation index, see [llms.txt](https://cantonindexer.infradao.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cantonindexer.infradao.com/milestones/m1.md).

# M1

Canton Indexer is the product the grant proposal calls Canton Index. This page lists what the proposal planned for Milestone 1, what was delivered, and what changed along the way.

The M1 tooling is `cinder`, a command-line tool for writing filters and testing them against a validator's PQS. Its binaries, release notes, example filters and the filter specification are in the public [canton-indexer-releases](https://github.com/InfraDAO/canton-indexer-releases) repository, where the M1 delivery post (2026-09-27) pointed reviewers. The source code is private; it will be published under the Apache 2.0 license by Milestone 4.

## Deliverables

| Planned                                                                                                                   | Delivered                                                                                                                                                                                                                                          | Where                                                                                                                                                                                                        |
| ------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| Filter specification reference with syntax, semantics and examples                                                        | `docs/filter-format.md`, published with v0.8.0 (2026-09-28) and unchanged since. This site carries the current text as [Filter format](/filter-format.md).                                                                                         | [filter-format.md at v0.8.0](https://github.com/InfraDAO/canton-indexer-releases/blob/v0.8.0/docs/filter-format.md)                                                                                          |
| Rust filter loader and validator, type-checked against the configured PQS source kind                                     | A filter is a TOML file. Loading it refuses unknown keys and checks `where` against the record type of its `source` (`lifecycle` or `exercises`): an unknown field, a path below a scalar value, or a literal of the wrong type fails validation.  | [Filter format: the `where` grammar](/filter-format.md#the-where-grammar)                                                                                                                                    |
| CLI to validate and test filters against sample Daml-LF JSON payloads, with a recorded fixture set                        | Replaced by the live loop: `cinder types`, `cinder preview` and `cinder run`, against a live PQS. `run` validates a filter before it runs it. The fixture set drives the test suites. See [Offline validate-and-test](#offline-validate-and-test). | [Tutorial](/tutorial.md); release notes [v0.4.0](https://github.com/InfraDAO/canton-indexer-releases/releases/tag/v0.4.0), [v0.5.0](https://github.com/InfraDAO/canton-indexer-releases/releases/tag/v0.5.0) |
| Unit tests covering all expression operators, coercion helpers and template matching rules                                | Unit tests for each `where` operator, each jq function the format allows at each arity, the coercion helpers, and exact template name matching. They run in CI in the source repository.                                                           | Source repository                                                                                                                                                                                            |
| At least 5 example filters: traffic purchases, reward collection, CC transfers, ANS operations, a CIP-0056 token transfer | 13 example filters, each with a test; 8 of the tests read recorded DevNet rows. See [Example filters](#example-filters).                                                                                                                           | [examples at v0.8.0](https://github.com/InfraDAO/canton-indexer-releases/tree/v0.8.0/examples)                                                                                                               |
| Design review checkpoint with DA engineering before Milestone 2                                                           | Design review calls with 5North and with the Canton Foundation. See [Design review](#design-review).                                                                                                                                               |                                                                                                                                                                                                              |

`select` expressions run on the embedded [jaq](https://github.com/01mf02/jaq) engine (version 3), with exact coercions for Daml-LF values: `decimal` and `int` for `Decimal` and `Int64` strings, `time` for timestamps (written in UTC), plus `party` and `one_of`. Since v0.8.0 a filter may call only the jq functions the format lists.

## Changes from the plan

Plans change as the work meets real data and feedback. Each change below is recorded for clarity: the plan, what was delivered, and why.

### Filter format

**Plan.** The proposal sketched filters in YAML, with `source: exercises` or `source: active` and an `as` target name, and said the syntax was not final.

**Delivered.** Filters are TOML files. `source` is `lifecycle` (contract creates and archives as one stream) or `exercises` (choice exercises), and `where` matches the template or choice by its full name. The keys are listed in [Filter format](/filter-format.md#keys).

**Why.** TOML keeps jq expressions readable without the escaping YAML would need. `lifecycle` reads PQS's `creates()` and `archives()` in place of `active()`; the reason is on the [Milestone 2 page](/milestones/m2.md#reader-and-cursor).

### Offline validate-and-test

**Plan.** A CLI tool to validate and test filters against sample Daml-LF JSON payloads, including a recorded fixture set.

**Delivered.** We prototyped an offline `run --fixtures` mode over recorded PQS rows, then made the live loop (`types` → `preview` → `run`) the authoring workflow instead. `types` lists the templates, interfaces and choices PQS holds, `preview` shows the records a `where` selects, and `run` validates the filter and writes its documents for a range of offsets. The [Tutorial](/tutorial.md) walks through the loop.

**Why.** The live loop shows authors the real records their `where` selects and the exact paths their `select` needs.

The recorded fixture set is in the source repository: 25 captured DevNet PQS rows in 20 files, plus JSON Ledger API captures. It drives tests of the filter engine and 8 of the 13 example filter tests; the other example tests use records shaped like PQS rows.

### Example filters

**Plan.** At least five examples: traffic purchases (`AmuletRules_BuyMemberTraffic`), reward collection, CC transfers, ANS operations, and a CIP-0056 token transfer.

**Delivered.** 13 examples, published with v0.8.0:

| Pattern           | Examples                                                                                  |
| ----------------- | ----------------------------------------------------------------------------------------- |
| Traffic purchases | `traffic-purchases` (`AmuletRules_BuyMemberTraffic`), `my-traffic-balance`                |
| Reward collection | `reward-collections`, `validator-rewards`, `validator-reward-claims`                      |
| CC transfers      | `token-transfers` (`AmuletRules_Transfer`)                                                |
| ANS operations    | `ans-operations`, `ans-entries`                                                           |
| Token standard    | `token-standard-transfers` (`EventLog_HoldingsChange`), `my-balance`, `holding-lifecycle` |
| Other             | `validator-licenses`, `report-active-calls`                                               |

The delivery post listed the seven examples of [v0.7.0](https://github.com/InfraDAO/canton-indexer-releases/tree/v0.7.0/examples). v0.8.0, published the next day, added the ANS, reward and token-standard transfer examples.

The token-standard examples read Token Standard V2 ([CIP-112](https://github.com/global-synchronizer-foundation/cips/blob/main/cip-0112/cip-0112.md)), not the CIP-0056 (V1) view the proposal names: `my-balance` and `holding-lifecycle` read the `HoldingV2` `Holding` view, and `token-standard-transfers` reads the V2 transfer events. CIP-112 is the V2 of the [CIP-0056](https://github.com/global-synchronizer-foundation/cips/blob/main/cip-0056/cip-0056.md) token standard.

### Design review

**Plan.** Share the filter format and example filters with DA engineering for feedback before proceeding to Milestone 2.

**Delivered.** During M1 we shared the filter format and example filters in design review calls with 5North and the Canton Foundation, and in the [delivery post](https://github.com/canton-foundation/canton-dev-fund/issues/817) of 2026-09-27, and asked for feedback. No feedback on the filter format has come back so far. A session with Digital Asset engineering is scheduled for the week of 2026-10-19.

Milestone 2 work continued in parallel, and we will incorporate feedback as it comes in.

## Sources

* Grant proposal, as merged: <https://github.com/canton-foundation/canton-dev-fund/blob/2a822687b422aea1f168e92cce545e692f8b0ac1/proposals/canton-index.md>
* Milestone 1 issue, with the delivery post (2026-09-27) and our reply on the design review and the fixtures: <https://github.com/canton-foundation/canton-dev-fund/issues/817>
* Releases repository: <https://github.com/InfraDAO/canton-indexer-releases>
* Filter specification at v0.8.0: <https://github.com/InfraDAO/canton-indexer-releases/blob/v0.8.0/docs/filter-format.md>
* Examples at v0.7.0 and v0.8.0: <https://github.com/InfraDAO/canton-indexer-releases/tree/v0.7.0/examples>, <https://github.com/InfraDAO/canton-indexer-releases/tree/v0.8.0/examples>
* Release notes v0.3.0 (exact coercions), v0.4.0 (`preview`), v0.5.0 (`preview --format json`), v0.8.0 (examples, jq function list): <https://github.com/InfraDAO/canton-indexer-releases/releases>
* CIP-0056, the Canton Network Token Standard: <https://github.com/global-synchronizer-foundation/cips/blob/main/cip-0056/cip-0056.md>
* CIP-112, Canton Network Token Standard V2: <https://github.com/global-synchronizer-foundation/cips/blob/main/cip-0112/cip-0112.md>
* jaq: <https://github.com/01mf02/jaq>
