Skip to main content

Config Reference

Chronicle publishes its configuration to config/chronicle.php.

driver​

Selects the storage driver Chronicle uses to persist entries.

'driver' => env('CHRONICLE_DRIVER', 'eloquent'),

Built-in drivers:

  • eloquent / database: synchronous write via Laravel's database layer (default)
  • queued: asynchronous write via a dedicated queue (a single worker, or a FIFO queue)
  • array: in-memory storage for tests
  • null: discards entries, useful for tests or local development

See Storage Drivers for full details on each driver.

connection​

Controls which Laravel database connection Chronicle uses for its tables.

'connection' => env('CHRONICLE_DB_CONNECTION'),

Set this when you want the audit ledger isolated from your main application database.

queue​

Used when driver = 'queued'. Chronicle chain hashes are order-sensitive, so entries must be persisted one at a time. On a queue that cannot guarantee ordering, that means a single worker:

php artisan queue:work --queue=chronicle --tries=1

Concurrent workers cannot fork the chain - sequence is uniquely indexed and the chain head is read under a row lock - but a losing write can fail and, with tries = 1, land in failed_jobs. An SQS FIFO queue removes that race (v1.14+). See Run Chronicle Writes on a Queue.

'queue' => [
'connection' => env('CHRONICLE_QUEUE_CONNECTION'),
'name' => env('CHRONICLE_QUEUE', 'chronicle'),
'message_group' => env('CHRONICLE_QUEUE_MESSAGE_GROUP', 'chronicle'),
],
KeyEnv varDefaultDescription
connectionCHRONICLE_QUEUE_CONNECTIONnull (default queue connection)Laravel queue connection to use
nameCHRONICLE_QUEUEchronicleQueue name for Chronicle jobs
message_groupCHRONICLE_QUEUE_MESSAGE_GROUPchronicleSQS message group every entry is dispatched under (v1.14+)

Notes:

  • A blank or null name dispatches to the queue connection's own default queue (v1.14+).
  • message_group must be one stable value: FIFO queues order messages only within a group, and the chain is a single global sequence. Change it only to namespace separate ledgers that share one queue. It must satisfy SQS's rules for a group ID (at most 128 characters, no whitespace). A blank or non-string value falls back to chronicle.
  • The group is sent on standard SQS queues too, where AWS treats it as a fair-queue marker with no ordering. Non-SQS queue drivers ignore it.

prune​

Used by chronicle:prune. Controls how old entries are retained.

'prune' => [
'default_retention_days' => env('CHRONICLE_RETENTION_DAYS'),
'respect_checkpoints' => true,
],
KeyDefaultDescription
default_retention_daysnull (disabled)Entries older than this many days are eligible for pruning
respect_checkpointstrueEntries anchored to a checkpoint are protected unless --force is passed

Set default_retention_days to null to disable time-based pruning entirely.

tables.entries​

Overrides the table used by Chronicle\Entry\Entry.

'tables' => [
'entries' => env('CHRONICLE_TABLE_ENTRIES', 'chronicle_entries'),
'checkpoints' => env('CHRONICLE_TABLE_CHECKPOINTS', 'chronicle_checkpoints'),
'checkpoint_anchors' => env('CHRONICLE_TABLE_CHECKPOINT_ANCHORS', 'chronicle_checkpoint_anchors'),
'verification_runs' => env('CHRONICLE_TABLE_VERIFICATION_RUNS', 'chronicle_verification_runs'),
],

Change this before running migrations if the default table name conflicts with your schema.

tables.checkpoints​

Overrides the table used for signed checkpoints.

This table stores the checkpoint chain head, entry count, signature metadata, and creation timestamp used to anchor the ledger state at a known moment in time.

models.entry​

'models' => [
'entry' => \Chronicle\Entry\Entry::class,
],

The Eloquent model Chronicle reads and verifies. Point it at a subclass of Chronicle\Entry\Entry to add accessors, relationships, casts, or scopes. New in v1.13; honored end-to-end by the query API, the reader, and all verifiers. The class must extend Chronicle\Entry\Entry or Chronicle throws InvalidEntryModelException. See Custom Entry Model.

references.label_attribute​

'references' => [
'label_attribute' => 'name',
],

The model attribute read for a human label when reverse reference resolution hydrates a record (Chronicle::referenceLabel(..., hydrate: true) / referenceModel()). Default name. New in v1.13. See Reference Resolution.

signing.active​

The key ID used to sign new checkpoints and exports. Must match a key defined in signing.keys.

'signing' => [
'active' => env('CHRONICLE_ACTIVE_KEY', 'chronicle-dev-key'),
],

signing.enforce_on_boot​

When true, Chronicle throws a RuntimeException at boot if the active key is missing or misconfigured. Only the active key is validated - retired verify-only keys in the ring are not checked.

'enforce_on_boot' => env('CHRONICLE_SIGNING_ENFORCE_ON_BOOT', false),

Silenced automatically in the testing environment.

signing.keys​

The full key ring. Each entry is a named key with its provider class, algorithm, and key material.

'signing' => [
'active' => env('CHRONICLE_ACTIVE_KEY', 'chronicle-dev-key'),
'keys' => [
'chronicle-dev-key' => [
'provider' => \Chronicle\Signing\Ed25519SigningProvider::class,
'algorithm' => 'ed25519',
'private_key' => env('CHRONICLE_PRIVATE_KEY'),
'public_key' => env('CHRONICLE_PUBLIC_KEY'),
],
],
],
Key entry fieldDescription
providerClass implementing Chronicle\Contracts\SigningProvider.
algorithmStable identifier stored in artifacts (e.g. 'ed25519', 'ecdsa-p256').
private_keySigning key material. Omit or set to null to create a verify-only retired key.
public_keyVerification key material. Required for all keys including retired ones.

Retired keys (keys without private_key) must remain in signing.keys permanently so that historic checkpoints and exports can continue to be verified.

See Signing & Keys for the full key ring documentation and rotation workflow.

anchoring​

External anchoring of checkpoints. Opt-in; off by default. See External Anchoring.

'anchoring' => [
'enabled' => env('CHRONICLE_ANCHORING_ENABLED', false),
'queue' => env('CHRONICLE_ANCHORING_QUEUE'),
'providers' => [
// 'rfc3161' => [
// 'provider' => \Chronicle\Anchoring\Rfc3161TimestampAnchor::class,
// 'tsa_url' => env('CHRONICLE_TSA_URL'),
// 'tsa_certificate' => env('CHRONICLE_TSA_CERTIFICATE'),
// ],
],
],
KeyEnvDefaultMeaning
anchoring.enabledCHRONICLE_ANCHORING_ENABLEDfalseAnchor each new checkpoint after commit
anchoring.queueCHRONICLE_ANCHORING_QUEUEnullQueue for the anchoring job (null = default)
anchoring.providers-[]name => ['provider' => class, ...config]

When enabled, each new checkpoint is anchored asynchronously with every configured provider after the checkpoint transaction commits. An anchor failure never rolls a checkpoint back.

Anchoring is not order-sensitive, so a standard queue is fine for anchoring.queue. A FIFO queue also works (v1.14+): anchor jobs are grouped by checkpoint, so different checkpoints still anchor in parallel.

validation​

Controls the configurable limits enforced by Chronicle's built-in validators.

'validation' => [
'action_max_length' => env('CHRONICLE_ACTION_MAX_LENGTH', 255),
'tag_max_length' => env('CHRONICLE_TAG_MAX_LENGTH', 50),
'tag_limit' => env('CHRONICLE_TAG_LIMIT', 10),
'correlation_id_max_length' => env('CHRONICLE_CORRELATION_ID_MAX_LENGTH', 255),
'max_payload_size' => env('CHRONICLE_MAX_PAYLOAD_SIZE', 65536),
],
KeyDefaultDescription
action_max_length255Maximum byte length of the action string
tag_max_length50Maximum UTF-8 character length of a single tag
tag_limit10Maximum number of tags per entry
correlation_id_max_length255Maximum UTF-8 character length of a correlation_id
max_payload_size65536Maximum byte size of the combined serialized metadata, context, and diff (64 KB)

See Validation for a full description of each built-in validator.

extensions​

Registers entry extensions that run before Chronicle's built-in pipeline stages.

'extensions' => [
ActorPresenceValidator::class,
SubjectValidator::class,
ActionValidator::class,
CorrelationValidator::class,
TagLimitValidator::class,
TagsValidator::class,
DiffStructureValidator::class,
PayloadSerializableValidator::class,
PayloadSizeValidator::class,
],

The default set contains Chronicle's built-in validators. Each extension must implement Chronicle\Contracts\EntryExtension. Extensions are executed before canonicalization, payload hashing, chain hashing, and persistence.

Remove a built-in validator from this array to disable it. Add your own classes to extend or replace validation logic.

ui​

Chronicle ships an optional read-only Blade interface. It is disabled by default.

'ui' => [
'enabled' => env('CHRONICLE_UI_ENABLED', false),
'prefix' => env('CHRONICLE_UI_PREFIX', 'chronicle'),
'middleware' => ['web', 'auth', 'can:view-chronicle'],
'per_page' => env('CHRONICLE_UI_PER_PAGE', 25),
],
KeyEnv varDefaultDescription
enabledCHRONICLE_UI_ENABLEDfalseSet to true to activate the web interface
prefixCHRONICLE_UI_PREFIXchronicleURL prefix for UI routes
middleware(PHP array, no env var)['web','auth','can:view-chronicle']Middleware stack applied to all UI routes
per_pageCHRONICLE_UI_PER_PAGE25Entries shown per page on the index

The can:view-chronicle gate must be defined in your AuthServiceProvider:

Gate::define('view-chronicle', fn ($user) => $user->isAdmin());

To allow any authenticated user, set middleware to ['web', 'auth'].

Note: middleware is a plain PHP array and cannot be driven by an environment variable - arbitrary middleware class names require code-level configuration.

Example production-oriented config​

return [
'driver' => env('CHRONICLE_DRIVER', 'eloquent'),
'connection' => env('CHRONICLE_DB_CONNECTION', 'audit'),
'tables' => [
'entries' => 'chronicle_entries',
'checkpoints' => 'chronicle_checkpoints',
'checkpoint_anchors' => 'chronicle_checkpoint_anchors',
'verification_runs' => 'chronicle_verification_runs',
],
'signing' => [
'enforce_on_boot' => env('CHRONICLE_SIGNING_ENFORCE_ON_BOOT', true),
'active' => env('CHRONICLE_ACTIVE_KEY', 'main'),
'keys' => [
'main' => [
'provider' => \Chronicle\Signing\Ed25519SigningProvider::class,
'algorithm' => 'ed25519',
'private_key' => env('CHRONICLE_PRIVATE_KEY'),
'public_key' => env('CHRONICLE_PUBLIC_KEY'),
],
],
],
'anchoring' => [
'enabled' => env('CHRONICLE_ANCHORING_ENABLED', false),
'queue' => env('CHRONICLE_ANCHORING_QUEUE'),
'providers' => [
// 'rfc3161' => [
// 'provider' => \Chronicle\Anchoring\Rfc3161TimestampAnchor::class,
// 'tsa_url' => env('CHRONICLE_TSA_URL'),
// 'tsa_certificate' => env('CHRONICLE_TSA_CERTIFICATE'),
// ],
],
],
'validation' => [
'action_max_length' => env('CHRONICLE_ACTION_MAX_LENGTH', 255),
'tag_max_length' => env('CHRONICLE_TAG_MAX_LENGTH', 50),
'tag_limit' => env('CHRONICLE_TAG_LIMIT', 10),
'correlation_id_max_length' => env('CHRONICLE_CORRELATION_ID_MAX_LENGTH', 255),
'max_payload_size' => env('CHRONICLE_MAX_PAYLOAD_SIZE', 65536),
],
'extensions' => [
\Chronicle\Validation\ActorPresenceValidator::class,
\Chronicle\Validation\SubjectValidator::class,
\Chronicle\Validation\ActionValidator::class,
\Chronicle\Validation\CorrelationValidator::class,
\Chronicle\Validation\TagLimitValidator::class,
\Chronicle\Validation\TagsValidator::class,
\Chronicle\Validation\DiffStructureValidator::class,
\Chronicle\Validation\PayloadSerializableValidator::class,
\Chronicle\Validation\PayloadSizeValidator::class,
],
];