CLI
Every carbon-cli 2.0.0 command and flag, the scaffold datasources, the generated project layout, environment variables and exit codes.
On this page
@sevenlabs-hq/ generates Carbon decoder crates from Anchor or Codama IDLs (parse) and scaffolds complete indexer workspaces around a generated decoder (scaffold). This page documents the published 2.0.0 package; its README lists only part of the flags.
Requirements: Node.js 20.18.0 or newer. cargo fmt (rustfmt) on your PATH to format the output; if it is missing the CLI prints a warning and leaves the code unformatted. The generated Rust code needs Rust 1.96.1 or newer.
Run the CLI#
Run it without installing, pinned to the version:
npx -y @sevenlabs-hq/carbon-cli@2.0.0 --helppnpm dlx @sevenlabs-hq/carbon-cli@2.0.0 --helpbunx @sevenlabs-hq/carbon-cli@2.0.0 --helpyarn dlx @sevenlabs-hq/carbon-cli@2.0.0 --helpA global install (npm install -g @sevenlabs-hq/) provides two identical binaries, carbon-cli and carbon. Commands on this page follow the runner you pick in any runner tab.
carbon-cli#
The root command. It dispatches to parse, scaffold and help.
carbon-cli [options] [command]Details.
| Option / command | Description |
|---|---|
-V, --version | Prints the version (2.0.0) and exits. |
-h, --help | Prints help with usage examples and exits. Works on every command (parse --help). |
help [command] | Same as --help for the root or for command. |
parse [options] | Generates a decoder crate. See parse. |
scaffold [options] | Generates an indexer workspace. See scaffold. |
Every parse and scaffold run prints an ASCII-art banner first. An unknown command or option exits with code 1 (error: unknown command 'foo').
Example.
npx -y @sevenlabs-hq/carbon-cli@2.0.0 --versionpnpm dlx @sevenlabs-hq/carbon-cli@2.0.0 --versionbunx @sevenlabs-hq/carbon-cli@2.0.0 --versionyarn dlx @sevenlabs-hq/carbon-cli@2.0.0 --version2.0.0See also. Exit codes, Interactive mode.
parse#
Generates a decoder crate from an IDL file or from the Anchor IDL stored on chain for a program address.
carbon-cli parse [options]Details. If --idl or --out-dir is missing, parse switches to interactive mode and prompts for them.
| Flag | Type | Default | Description |
|---|---|---|---|
-i, --idl < | path or base58 address | prompted | A path ending in .json, or a program address (base58, 32 to 44 characters). Anything else exits with Invalid IDL: must be a .. |
-o, --out-dir < | path | prompted (./generated) | Directory the crate is written to, resolved against the current directory. Deleted and recreated unless you pass --no-clean. |
-n, --name < | string | IDL program name | Decoder name. Whitespace becomes -. Produces the crate carbon-< (kebab case) and the struct < (Pascal case). |
-s, --standard < | anchor or codama | anchor | IDL format. Program addresses support anchor only. |
-u, --url < | URL or alias | none | RPC endpoint for fetching the IDL; required when --idl is a program address. See details. |
--program-id < | base58 address | none | Program ID for an IDL without one. Required for every Codama IDL. See details. |
--event-hints < | comma-separated names | none | Codama only. Has no effect in 2.0.0. See details. |
--event-cpi-discriminator < | even-length hex, optional 0x | e445a52e51cb9a1d | Codama only. Envelope prefix of hidden-prefix event CPIs. |
--postgres-mode < | generic or typed | typed | typed generates per-account and per-instruction row types, tables and migrations (accounts::, instructions::). generic skips them; you store data as JSON with the generic processors. See Postgres. |
--with-postgres < | true or false | true | Generates the Postgres modules and a postgres Cargo feature. |
--with-graphql < | true or false | true | Generates the GraphQL modules and a graphql Cargo feature. |
--with-serde < | true or false | false, or true when both flags above are false | Declares the serde feature. postgres and graphql enable it on their own. |
--with-base58 < | true or false | false | Adds a base58 feature (implies serde) that serializes Pubkey fields as base58 strings. |
--standalone < | true or false | true | false makes every dependency { workspace = true }, for crates inside a Cargo workspace. |
--description < | string | derived from the name | Package description. |
--keywords < | comma-separated | solana, decoder and the name parts | Package keywords. |
--categories < | comma-separated | encoding | Package categories. |
--package-version < | semver | 0.1.0 | version in the decoder's Cargo.toml. |
--version-name < | string | none | Appends -<name> to the crate name (carbon-dex-decoder-v1) for versioned decoders. |
--no-clean | flag | cleaning on | Keeps the existing contents of --out-dir and writes over them. |
-c, --as-crate | flag | false | Accepted but has no effect in 2.0.0: the output is always a crate. |
Boolean flags take a value: write --with-postgres false. Only the literal string true is true; yes, 1 or TRUE count as false. --description, --keywords and --categories are written to Cargo.toml only when at least one of them is passed.
Parse flag details#
--url.mainnet-betaanddevnetexpand tohttps:/and/ api. mainnet-beta. solana. com https:/; any other value is used as is./ api. devnet. solana. com --program-id. For an Anchor IDL, the value is written toPROGRAM_IDwhen the IDL has no validaddress(ormetadata.) and ignored when it has one. For a Codama IDL it's required, because the CLI checks onlyaddress addressandmetadata., notaddress program.. Without it,publicKey parseexits with code 2:Program ID is required. IDL missing or invalid address field - provide via --program-id parameter. The value is then ignored:PROGRAM_IDcomes fromprogram..publicKey --event-hints. Accepted for compatibility but never passed to the renderer, so the output is byte-identical with and without it. Event types and theCpiEventvariant are generated only from native CodamaeventNodes. Passing it with-s anchorexits with code 2.--standalone.trueadds an empty[workspace]table so the crate builds on its own.falsewrites every dependency as{ workspace = true }, so the parent workspace must define them in[workspace..dependencies]
When --idl is a program address, the CLI reads the program's Anchor IDL account with @coral-xyz/ at confirmed commitment. Programs that never ran anchor idl init exit with No Anchor IDL found for program address.
The generated crate depends on carbon-core = { version = "2., borsh, solana-pubkey, solana-account, solana-instruction and serde_json, with serde, sqlx, sqlx_, async-trait and juniper as optional dependencies behind its features. Its layout:
- <out-dir>/
- Cargo.toml
- src/
- lib.rs<Name>Decoder, PROGRAM_ID, EVENT_CPI_DISCRIMINATOR (when the IDL has events)
- accounts/<Name>Account enum + one file per account; postgres/ and graphql/ when enabled
- instructions/<Name>Instruction enum + one file per instruction (and cpi_event.rs); postgres/, graphql/
- events/one file per event, when the IDL has events
- types/defined types; graphql/ when enabled
- graphql/context.rs, query.rs (QueryRoot), when --with-graphql true
Directories with nothing to generate are omitted. See Feature flags for the decoder's Cargo features.
Example. Generate a decoder for Pump.fun AMM from its on-chain IDL:
npx -y @sevenlabs-hq/carbon-cli@2.0.0 parse \
--idl pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA \
--url mainnet-beta \
--name pump-amm \
--out-dir ./pump-amm-decoderpnpm dlx @sevenlabs-hq/carbon-cli@2.0.0 parse \
--idl pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA \
--url mainnet-beta \
--name pump-amm \
--out-dir ./pump-amm-decoderbunx @sevenlabs-hq/carbon-cli@2.0.0 parse \
--idl pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA \
--url mainnet-beta \
--name pump-amm \
--out-dir ./pump-amm-decoderyarn dlx @sevenlabs-hq/carbon-cli@2.0.0 parse \
--idl pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA \
--url mainnet-beta \
--name pump-amm \
--out-dir ./pump-amm-decoder✔ Decoder generated
✔ Code formatted successfully
✨ Decoder Generated Successfully! ✨
• Output: /home/you/pump-amm-decoder
• Source: program-address (anchor) @ https://api.mainnet-beta.solana.comWith --postgres-mode generic, the crate keeps its postgres feature but has no typed tables: compared with the default typed output above, src/ and src/ are not generated. Store decoded data as JSON with the generic processors instead:
npx -y @sevenlabs-hq/carbon-cli@2.0.0 parse \
--idl pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA \
--url mainnet-beta \
--name pump-amm \
--out-dir ./pump-amm-decoder \
--postgres-mode genericpnpm dlx @sevenlabs-hq/carbon-cli@2.0.0 parse \
--idl pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA \
--url mainnet-beta \
--name pump-amm \
--out-dir ./pump-amm-decoder \
--postgres-mode genericbunx @sevenlabs-hq/carbon-cli@2.0.0 parse \
--idl pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA \
--url mainnet-beta \
--name pump-amm \
--out-dir ./pump-amm-decoder \
--postgres-mode genericyarn dlx @sevenlabs-hq/carbon-cli@2.0.0 parse \
--idl pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA \
--url mainnet-beta \
--name pump-amm \
--out-dir ./pump-amm-decoder \
--postgres-mode genericFrom a local Codama IDL. --program-id is required for Codama files even though the generated PROGRAM_ID is read from the IDL's program.:
npx -y @sevenlabs-hq/carbon-cli@2.0.0 parse -i ./codama.json -s codama --program-id <ProgramAddress> -o ./decoderpnpm dlx @sevenlabs-hq/carbon-cli@2.0.0 parse -i ./codama.json -s codama --program-id <ProgramAddress> -o ./decoderbunx @sevenlabs-hq/carbon-cli@2.0.0 parse -i ./codama.json -s codama --program-id <ProgramAddress> -o ./decoderyarn dlx @sevenlabs-hq/carbon-cli@2.0.0 parse -i ./codama.json -s codama --program-id <ProgramAddress> -o ./decoderSee also. Generate a decoder, Decoders, scaffold.
scaffold#
Generates a Cargo workspace with a decoder generated from your IDL and an indexer binary wired to a datasource, metrics and, optionally, Postgres and GraphQL.
carbon-cli scaffold [options]Details. If any of --name, --out-dir, --data-source or --idl is missing, scaffold switches to interactive mode and prompts for the missing values.
| Flag | Type | Default | Description |
|---|---|---|---|
-n, --name < | string | prompted | Project directory name. The indexer package is named <. Not validated on the command line; the prompt accepts lowercase letters, digits and - only. |
-o, --out-dir < | path | prompted (.) | Parent directory. The project goes to <. |
--idl < | path or base58 address | prompted | IDL file (.json) or program address. Same rules as parse --idl. |
--idl-standard < | anchor or codama | anchor (prompted in interactive mode) | IDL format. Program addresses support anchor only. |
--idl-url < | URL or alias | none | RPC endpoint for fetching the IDL of a program address; required in that case. Accepts the mainnet-beta and devnet aliases. |
-d, --decoder < | string | IDL program name | Decoder name. Generates carbon-< in decoder/ and the Rust names <, <, < (each --separated part capitalized: pump-amm gives PumpAmm). Without it the name comes from the IDL's name, program. or metadata., kebab-cased, else custom-decoder. |
-s, --data-source < | see Datasources | prompted | Datasource the indexer uses. Any other value exits with code 2. |
-m, --metrics < | log or prometheus | log | log registers LogMetrics:: (logs every 5 s); prometheus registers PrometheusMetrics:: (scrape endpoint on 0.). See Metrics. |
--with-postgres < | true or false | true | Wires Postgres: connects to DATABASE_, runs migrations and stores accounts and instructions. |
--with-graphql < | true or false | true | Serves a GraphQL API over the Postgres data on 0.. Requires --with-postgres true. |
--postgres-mode < | generic or typed | typed | Table layout; see parse. |
--with-serde < | true or false | false, or true when Postgres and GraphQL are both off | Enables the decoder's serde feature. |
--with-base58 < | true or false | false | Enables the decoder's base58 feature. |
--event-hints < | comma-separated names | none | Codama only. No effect in 2.0.0; see parse. |
--event-cpi-discriminator < | even-length hex | e445a52e51cb9a1d | Codama only; see parse. |
--program-id < | base58 address | none | Program ID when an Anchor IDL has no valid address. Required for every Codama IDL file, where its value is ignored; see parse. |
--package-version < | semver | 0.1.0 | Version of the generated decoder crate. The indexer is always 0.0.1. |
--version-name < | string | none | Renames the decoder crate to carbon-<. Breaks the scaffold in 2.0.0; see Known issues. |
--force | flag | false | Writes into an existing <. decoder/ is deleted and regenerated; the other generated files are overwritten; files the CLI does not generate are kept. Without it an existing directory exits with code 2. |
scaffold always generates the decoder in decoder/ with standalone: false and pinned crates.io versions, so the workspace builds on its own. Because --with-graphql defaults to true, --with-postgres false alone exits with GraphQL scaffolding requires Postgres. Enable --with-postgres or disable --with-graphql.; pass both flags.
Example. A Postgres-free indexer that crawls Pump.fun AMM transactions over RPC:
npx -y @sevenlabs-hq/carbon-cli@2.0.0 scaffold \
--name my-indexer \
--out-dir . \
--idl pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA \
--idl-url mainnet-beta \
--decoder pump-amm \
--data-source rpc-transaction-crawler \
--with-postgres false \
--with-graphql falsepnpm dlx @sevenlabs-hq/carbon-cli@2.0.0 scaffold \
--name my-indexer \
--out-dir . \
--idl pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA \
--idl-url mainnet-beta \
--decoder pump-amm \
--data-source rpc-transaction-crawler \
--with-postgres false \
--with-graphql falsebunx @sevenlabs-hq/carbon-cli@2.0.0 scaffold \
--name my-indexer \
--out-dir . \
--idl pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA \
--idl-url mainnet-beta \
--decoder pump-amm \
--data-source rpc-transaction-crawler \
--with-postgres false \
--with-graphql falseyarn dlx @sevenlabs-hq/carbon-cli@2.0.0 scaffold \
--name my-indexer \
--out-dir . \
--idl pAMMBay6oceH9fJKBRHGP5D4bD4sWpmSwMn52FMfXEA \
--idl-url mainnet-beta \
--decoder pump-amm \
--data-source rpc-transaction-crawler \
--with-postgres false \
--with-graphql falseℹ Using provided decoder name: pump-amm
✔ Project structure created
✔ Decoder generated successfully
✔ Code formatted successfully
✨ Scaffold Created Successfully! ✨
• Location: /home/you/my-indexer
• Decoder: pump-amm (generated from IDL)Set the RPC endpoint in .env, then run the indexer from the workspace root:
RPC_URL=https://api.mainnet-beta.solana.comcd my-indexer
RUST_LOG=info cargo run -p my-indexer-indexer[2026-11-09T00:04:31Z INFO carbon_core::pipeline] starting pipeline. num_datasources: 1, num_exporters: 1, num_account_pipes: 0, num_account_deletion_pipes: 0, num_instruction_pipes: 1, num_transaction_pipes: 0
[2026-11-09T00:04:31Z INFO carbon_log_metrics] 00:00:00 (+3.354806ms) | 0 processed (0%), 0 successful, 0 failed (0%), 0 in queueSee also. Generated project, Environment variables, Datasources, Quickstart.
Scaffold datasources#
--data-source accepts exactly these five values. Each adds the datasource crate at 2.0.0 and the extra Solana crates its setup code needs.
| Value | Datasource | Reads | What the generated code subscribes to |
|---|---|---|---|
rpc-transaction-crawler | RpcTransactionCrawler | RPC_URL (no fallback: an empty URL) | Transactions that mention the decoder's PROGRAM_ID, newest first, at finalized commitment, 100 signatures per batch, polling every 5 s, 5 concurrent requests, default retries. Works on the public endpoint. |
rpc-block-subscribe | RpcBlockSubscribe | RPC_WS_URL (falls back to wss:/) | Every transaction in every block (RpcBlockSubscribeFilter::), Base64 encoding, full details, transaction versions up to 1. The public endpoint rejects blockSubscribe; use a provider that supports it. |
rpc-program-subscribe | RpcProgramSubscribe | RPC_WS_URL (falls back to wss:/) | Account updates for accounts owned by PROGRAM_ID, Base64 encoding. Emits account updates only. |
yellowstone-grpc | YellowstoneGrpcGeyserClient | GEYSER_URL, X_TOKEN (optional) | Accounts owned by PROGRAM_ID, plus successful non-vote transactions that include it, at Confirmed commitment. |
helius-laserstream | LaserStreamGeyserClient | GEYSER_URL, X_TOKEN (optional) | Same filters as yellowstone-grpc, through LaserStream with LaserStreamClientConfig::. |
The two gRPC datasources also add rustls and yellowstone-grpc-proto = "=12., and main installs the aws-lc-rs crypto provider before connecting.
Generated project#
scaffold writes this tree (shown for --name my-indexer with the defaults, Postgres and GraphQL on):
- my-indexer/
- .envplaceholder values, see Environment variables
- .gitignoredebug/, target/, .env, .DS_Store
- Cargo.toml[workspace] members = ["indexer", "decoder"]
- README.mdrun command and the options you chose
- decoder/carbon-<decoder>-decoder, same layout as
parseoutput- Cargo.toml
- src/
- indexer/
- Cargo.tomlpackage my-indexer-indexer, rust-version 1.96.1
- src/
- main.rs
indexer/ does the following, in order:
- Initializes
env_logger, then loads.envwithdotenv. - With Postgres: connects to
DATABASE_, then runs the decoder's migrations (URL <andName>AccountsMigration <, orName>InstructionsMigration GenericAccountsMigrationandGenericInstructionMigrationingenericmode) throughsqlx_.migrator - Builds the datasource as described in Scaffold datasources.
- Builds a pipeline with the metrics exporter and
ShutdownStrategy::, and registers:Immediate - with Postgres:
.andaccount(< Name>Decoder, PostgresAccountProcessor:: < …>:: new(pool)) .(instruction(< Name>Decoder, PostgresInstructionProcessor:: < …>:: new(pool)) PostgresJsonAccountProcessorandPostgresJsonInstructionProcessoringenericmode); - without Postgres:
., a stub processor ininstruction(< Name>Decoder, < Name>InstructionProcessor) main.rsthat logsreceived the <atName> instruction, sig: < signature> infolevel and has an emptymatchfor you to fill in.
- with Postgres:
- With GraphQL: runs the pipeline and an Axum server side by side with
tokio::, servingselect! http:/and GraphiQL at/ 0. 0. 0. 0:8080/ graphql /graphiql. The process stops when either finishes.
Generated indexer/ dependencies: carbon-core = "2. (default features off; postgres/graphql features when enabled), the decoder by path, the datasource and metrics crates at 2.0.0, tokio 1 (rt-multi-thread, macros), dotenv 0.15, env_logger 0.11.8, log 0.4.28, plus sqlx 0.8.6 and sqlx_ 0.17 with Postgres and axum 0.8.7 with GraphQL.
Interactive mode#
Run parse or scaffold without the required flags and the CLI prompts for what is missing. Flags you pass are used as answers and their prompts are skipped.
parse prompts for, in order:
- IDL file or program address
- Output directory (
./generated) - RPC URL (
mainnet-beta), for an address - Event hints, with
-s codama(no effect) - Program ID, when the IDL has no address (every Codama IDL)
scaffold prompts for, in order:
- Project name
- Output directory (
.) - Overwrite confirmation, if
<exists (no exits with code 1)out-dir>/ < name> - IDL file or program address
- RPC URL (
mainnet-beta) for an address, or IDL standard for a file - Program ID, when the IDL has no address
- Decoder name (Enter auto-detects)
- Data source
- Add Postgres (
Y) - Enable GraphQL (
Y, only with Postgres)
Options that have a default never prompt: parse uses anchor for the standard and cleans the output directory, and both commands use typed for --postgres-mode; scaffold uses log metrics. Pass the flag to choose otherwise. Ctrl+C at a prompt exits with code 1 and a stack trace.
Environment variables#
The CLI itself reads no environment variables. The scaffolded indexer reads these, from the shell or from .env in the directory you run it from:
| Variable | Used when | Behaviour when unset |
|---|---|---|
DATABASE_ | --with-postgres true | Panics: DATABASE_. |
RPC_URL | rpc-transaction-crawler | Empty URL; every request fails. |
RPC_WS_URL | rpc-block-subscribe, rpc-program-subscribe | wss:/. |
GEYSER_URL | yellowstone-grpc, helius-laserstream | Empty URL; the connection fails. |
X_TOKEN | yellowstone-grpc, helius-laserstream | No x-token header is sent. |
RUST_LOG | always (env_logger) | Only errors are logged. |
The generated .env contains DATABASE_ (with Postgres) and one placeholder per datasource variable, such as RPC_ or X_. Replace them; delete X_TOKEN if your endpoint needs no token, or the placeholder is sent as the token.
Exit codes#
| Code | Meaning |
|---|---|
0 | Success. A cargo fmt failure still exits 0 after a Formatting failed warning. |
1 | A usage error from the argument parser, or an unhandled exception with a Node.js stack trace. Examples below. |
2 | A validation error, printed as ✗ Error: <. |
Code 1 covers usage errors such as error: unknown option '--bogus', error: option '-i, --idl < or an unknown command, and unhandled exceptions: an IDL file that doesn't exist (ENOENT), invalid JSON, a Codama run on an Anchor IDL, Ctrl+C at a prompt, or declining the overwrite prompt.
Messages that exit with code 2:
Invalid IDL: must be a .json file or a Solana program address IDL standard must be 'anchor' or 'codama'Codama standard is only supported with IDL files, not program addressesRPC URL is required when using a program addressEvent hints can only be used with Codama standard--event-cpi-discriminator can only be used with Codama standardInvalid --event-cpi-discriminator: expected an even-length hex string (e.g. e445a52e51cb9a1d) Program ID cannot be empty,Invalid Program ID format (must be base58, 32-44 characters)Program ID is required. IDL missing or invalid address field - provide via --program-id parameterNo Anchor IDL found for program address.,Failed to fetch Anchor IDL: <reason> Invalid data source. Must be one of: helius-laserstream, rpc-block-subscribe, rpc-program-subscribe, rpc-transaction-crawler, yellowstone-grpcMetrics must be 'log' or 'prometheus'GraphQL scaffolding requires Postgres. Enable --with-postgres or disable --with-graphql.Output directory already exists: <path> (use --force to overwrite)
Known issues#
These are 2.0.0 behaviours to work around:
parsedeletes--out-dir. Point it at a dedicated directory, never.or a directory with your own files, or pass--no-clean.scaffold --version-nameproduces a workspace that does not build. The decoder crate becomescarbon-<butname>-decoder-< version> indexer/still depends onCargo. toml carbon-<, so Cargo fails withname>-decoder no matching package named `carbon-<. Usename>-decoder` found parse --version-namefor versioned decoders and wire them yourself (Versioned decoders).- Pipes that never fire. The scaffold registers the same pipes for every datasource.
rpc-transaction-crawlerandrpc-block-subscribeemit no account updates, so the account pipe stays idle.rpc-program-subscribeemits only account updates, so without Postgres (instruction pipe only) the indexer processes nothing. Add an.pipe for program-subscribe projects.account(. . . ) rpc-block-subscribeon the public endpoint. The fallbackwss:/rejects/ api. mainnet-beta. solana. com/ blockSubscribewithMethod not found. SetRPC_WS_URLto a provider that supports it, and narrow the filter inmain.rs: the generatedRpcBlockSubscribeFilter::streams every transaction on the network.All - Help text says
--with-serdedefaults tofalse. It defaults totruewhen both--with-postgresand--with-graphqlarefalse. -c,--as-cratedoes nothing.--event-hintsdoes nothing. It is validated (Codama only) but never reaches the renderer. Model events as CodamaeventNodes instead.- Codama IDLs need
--program-id. The CLI looks foraddressormetadata.and ignoresaddress program., so a Codama file withoutpublicKey --program-idexits with code 2:Program ID is required. IDL missing or invalid address field - provide via --program-id parameter. Pass the program address; the generatedPROGRAM_IDstill comes fromprogram., whatever value you pass.publicKey - Indexer package name. It is always
<, soname>-indexer --name my-indexergivesmy-indexer-indexer.