Overview
This guide covers how to upgrade Clavion/ISCL between versions safely. The current release is v0.1.0. All upgrade procedures prioritize backward compatibility, data safety, and zero-downtime patterns where possible. Clavion uses three schema version fields, a/v1/ API prefix, and semantic versioning for the project itself. Within the v0.x release series, upgrades are designed to be non-destructive: existing databases, keystore files, and policy configurations remain valid across minor and patch updates.
Versioning strategy
Clavion tracks versions at three levels:Schema versions
Embedded in data structures and validated at runtime:TxIntent.version: "1"— transaction intent format used by all five action typesPolicyConfig.version: "1"— policy configuration format with 10 required fieldsSkillManifest.version: "1"— skill registration manifest format
API versioning
All HTTP endpoints use the/v1/ prefix. A major version bump to /v2/ would indicate breaking changes to the request/response format.
Project versioning
Follows semantic versioning (MAJOR.MINOR.PATCH):
MAJOR— breaking schema or API changesMINOR— new features, new optional fields, new endpointsPATCH— bug fixes, documentation, internal refactoring
Current schema summary
| Schema | Version | Key Fields | Reference |
|---|---|---|---|
| TxIntent | "1" | id, chain, wallet, action (5 types: transfer, approve, swap_exact_in, swap_exact_out, transfer_native), constraints | packages/types/src/index.ts |
| PolicyConfig | "1" | maxValueWei, maxApprovalAmount, contractAllowlist, tokenAllowlist, allowedChains, recipientAllowlist, maxRiskScore, requireApprovalAbove, maxTxPerHour | packages/policy/src/policy-config.ts |
| SkillManifest | "1" | name, publisher (name, address, contact), permissions (txActions, chains, networkAccess, filesystemAccess), sandbox (memoryMb, timeoutMs, allowSpawn), files (path, sha256), signature | packages/types/src/index.ts |
Backward compatibility policy
These rules govern how schemas evolve within and across major versions.
- New optional fields can be added within a major version without breaking existing clients. For example,
TxIntent.preferencesandTxIntent.metadataare optional and were added without a version bump. additionalProperties: falseis enforced on all schemas via AJV strict mode. Clients must not send fields that are not in the schema — unknown properties cause validation errors, not silent acceptance.- v1 schemas are supported throughout the entire 0.x release series. A TxIntent with
version: "1"will remain valid until at least v1.0.0. - Breaking changes (removing a field, changing a field type, changing validation rules) require a major version bump and will be documented with migration instructions.
Upgrade procedure
Database migration
The SQLite audit database uses
CREATE TABLE IF NOT EXISTS and CREATE INDEX IF NOT EXISTS patterns. This means:- New tables (e.g.,
rate_limit_events) are created automatically on first startup after an upgrade. - New indexes (e.g.,
idx_rate_wallet_ts) are added automatically without manual intervention. - Existing data is never deleted or altered by schema changes. All DDL operations in v0.x are additive.
- The database uses WAL journal mode (
journal_mode = WAL) for concurrent read access during writes.
Policy configuration
Policy configuration files are validated against
PolicyConfigSchema on load:- The
getDefaultConfig()function provides sensible defaults for all 10 required fields. If no policy file exists at the configured path, these defaults are used automatically. - Existing policy JSON files remain valid as long as they conform to the current
PolicyConfigSchema. No fields have been removed in v0.x. - If a future version adds a new required field, the AJV validation error message will indicate exactly which field is missing and what format it expects.
Keystore files
The encrypted keystore uses a stable format that does not change between v0.x releases:
- Encryption: AES-256-GCM with scrypt key derivation (N=262144, r=8, p=1)
- Metadata file:
keystore.jsonwithversion: "1"tracks all key entries - Key files: Individual
.encfiles per address, named{address_prefix}-{profile}.enc
EncryptedKeystore class reads the kdfParams from each key file at unlock time, so even if scrypt parameters change in a future version, existing key files will continue to work with their original parameters.Breaking change policy
When breaking changes are unavoidable, the following process applies:- Deprecation notice in a minor version release, logged as a warning at startup.
- Migration guide published alongside the breaking release, with before/after examples.
- Major version bump for any change that breaks existing schemas, API contracts, or data formats.
- Per-change instructions in the CHANGELOG explaining exactly what to update and in what order.
What requires a major version bump
- Removing a required field from
PolicyConfig - Changing
TxIntent.versionfrom"1"to"2" - Altering the API response format for
/v1/tx/build - Changing the keystore encryption scheme (old files would still be readable)
What does NOT require a major version bump
- Adding a new optional field to
TxIntent.metadata - Adding a new action type (e.g.,
"bridge") toActionObject - Adding a new API endpoint under
/v1/ - Adding a new index to the audit database
Rollback
If an upgrade causes issues, roll back with these steps.- Docker rollback
- Source rollback
Data compatibility during rollback
- SQLite: Backward compatible. New tables and columns added by a newer version are silently ignored by older code. The
CREATE TABLE IF NOT EXISTSpattern means older code will not fail on encountering tables it does not use. - Policy config: Files work across versions within the same major version. A policy file valid for v0.1.0 will also be valid for v0.2.0 and vice versa, as long as both are in the v0.x series.
- Keystore files: Always backward compatible. The encryption format is versioned independently and has not changed.
Troubleshooting
Common issues encountered during upgrades:| Symptom | Cause | Fix |
|---|---|---|
Invalid policy config: /: must have required property 'X' | A new required field was added to PolicyConfig in this version | Add the missing field to your policy JSON. Check getDefaultConfig() in packages/policy/src/policy-config.ts for the default value. |
must NOT have additional properties from AJV | Your request or config contains a field not in the schema | Remove the unrecognized field. All schemas use additionalProperties: false. |
Cannot find module '@clavion/...' | Dependencies not rebuilt after code update | Run npm install && npm run build to rebuild all packages in dependency order. |
SQLITE_BUSY: database is locked | Another ISCL process is still running | Stop all ISCL processes before upgrading: docker compose down or kill the Node process. |
Invalid passphrase or corrupted key file | Keystore file damaged or wrong passphrase | Restore from backup. Keystore files should be backed up before every upgrade. |
| Fastify route not found (404) | Stale build artifacts | Run npm run build to rebuild. Delete dist/ directories if the issue persists. |
ERR_MODULE_NOT_FOUND for CJS packages | ESM/CJS interop issue after dependency update | Verify that ajv-formats and canonicalize still use the createRequire import pattern. |
Pre-upgrade checklist
Use this checklist before every upgrade:Read release notes / CHANGELOG for the target version
Check for breaking changes, new required fields, and migration instructions.
Confirm policy config is valid against new schema
Run
npm run test:unit to validate your policy configuration.Next steps
- Configuration Reference — All configuration options
- Production Deployment — Deployment guidance
- Audit Trail — Event logging and forensics