Seed folder structure
The seed/ folder contains instances of Types that mix the SeedData base Type. The C3 Agentic AI Platform deploys these instances to the database during package provisioning to provide initial persistent data for your application. This topic explains what belongs in this folder, how the C3 Agentic AI Platform deploys and manages seed data, and how user permissions control data modification.
Understand what belongs in seed/
The seed folder stores instances of Types that mix SeedData. These are initial database records deployed during package provisioning, such as cron jobs, Jupyter files, default configurations, reference data, and system entities.
Examples:
seed/
CronJob/
BackupDatabase.json
CleanupLogs.json
JupyterFile/
AlertInfoTool.json
DataAnalysisTool.jsonType requirements
Types stored in the seed folder must meet specific requirements:
- Mix the SeedData base type (for example,
SeedData<CronJob>). - Be entity types with database persistence.
- Typically include
@seedannotation to control user permissions.
These requirements enable the C3 Agentic AI Platform to deploy instances to the database and manage their lifecycle.
File formats
The C3 Agentic AI Platform supports two file formats for seed data:
JSON files (*.json)
JSON is the standard format for seed data instances. Each file contains a single instance or an array of instances.
seed/CronJob/BackupDatabase.json
{
"id": "backup-database",
"name": "Database Backup Job",
"description": "Periodically backup the database",
"action": {
"actionName": "backupDatabase",
"typeName": "DatabaseManager"
},
"scheduleDef": {
"cronExpression": "0 0 2 * * ?",
"skipOverdue": true
},
"inactive": false
}Single instance: The id field identifies the instance in the database.
Multiple instances: Use an array to define multiple instances in one file.
seed/CronJob/maintenance-jobs.json
[
{
"id": "cleanup-logs",
"name": "Log Cleanup Job",
"description": "Remove old log files",
"action": {
"actionName": "cleanupLogs",
"typeName": "LogManager"
},
"scheduleDef": {
"cronExpression": "0 0 3 * * ?"
}
},
{
"id": "archive-data",
"name": "Data Archive Job",
"description": "Archive old records",
"action": {
"actionName": "archiveData",
"typeName": "DataManager"
},
"scheduleDef": {
"cronExpression": "0 0 4 * * ?"
}
}
]CSV files (*.csv)
CSV format is efficient for bulk seed data instances. Each row after the header creates one database record.
seed/Unit/Unit.csv
id,symbol,name
meter,m,Meter
kilogram,kg,Kilogram
second,s,Second
celsius,°C,Celsius
watt,W,Watt
pascal,Pa,PascalThis CSV file creates six Unit instances in the database.
Row 1 (header): Defines the field mappings - id, symbol, and name correspond to Unit fields.
Row 2: Creates a Unit instance with id "meter", symbol "m", and name "Meter".
Row 3: Creates a Unit instance with id "kilogram", symbol "kg", and name "Kilogram".
Row 4: Creates a Unit instance with id "second", symbol "s", and name "Second".
Additional rows create Unit instances for celsius (°C), watt (W), and pascal (Pa).
How seed/ relates to other folders
Several folders depend on or interact with the content in your seed/ folder.
Source folder (
src/) The seed folder references Types declared insrc/. When you change a Type definition, the C3 Agentic AI Platform revalidates seed data against the new Type structure during deployment. See Source Folder.Data folder (
data/) Both seed and data folders can contain instances for database persistence, and both are collected during automatic provisioning when the package fingerprint changes. However, they serve different purposes. The seed folder stores instances of Types that mix SeedData, which provide initial data with special upgrade-preservation features and dual-ownership semantics. The data folder stores instances of regular Persistable types (that don't mixSeedData,Metadata, orConfig), which undergo standard persistence without the sophisticated field-level tracking and user modification preservation thatSeedDataprovides.Use seed for configuration and defaults that need to survive upgrades with user customizations intact. Use data for regular entity instances and test data. See Data Folder.
Metadata folder (
metadata/) Both seed and metadata store Type instances, but they serve fundamentally different purposes. Seed data contains initial database records deployed during provisioning. Metadata contains runtime configuration loaded into memory. Seed data persists in the database and supports user modification. Metadata loads from files and supports remixing. See Metadata Folder.Test folder (
test/) Test seed data intest/seed/provides initial database records for tests. The C3 Agentic AI Platform deploys test seed data in test mode, allowing you to override or extend production seed data. See Test Folder.
These interactions make the seed/ folder a key part of your package's database initialization.
Structural rules
The C3 Agentic AI Platform enforces structural rules in the seed/ folder to discover instances, validate them, and deploy them reliably.
Path conventions
The directory structure determines which Type the seed data belongs to.
Standard path structure:
/packageName/seed/TypeName/instanceName.extThe directory name (second-to-last path segment) identifies the Type. For example:
seed/CronJob/BackupDatabase.json: Type is CronJob.seed/JupyterFile/AlertInfoTool.json: Type is JupyterFile.seed/Unit/Unit.csv: Type is Unit.
File naming
Instance filenames should reflect the content but don't need to match the id field. The C3 Agentic AI Platform uses the id field from the instance data to identify records in the database.
Example:
seed/CronJob/backup-database.json
{
"id": "db-backup-job", // ID used in database
...
}The filename backup-database.json describes the content, while the id field "db-backup-job" identifies the database record.
Validation rules
The C3 Agentic AI Platform validates seed data files before deployment and reports issues through Pkg.Issue.
Below are examples of validation rules:
Required fields: Missing required fields generate errors.
// Error: Missing required field
{
"id": "backup-job"
// Missing required "action" field for CronJob
}Invalid fields: Fields not declared in the Type generate errors.
// Error: Invalid field
{
"id": "backup-job",
"action": {...},
"invalidField": true // Type does not declare this field
}Type mismatches: Field values must match the declared Type.
// Error: Type mismatch
{
"id": "backup-job",
"action": "should be object" // Field expects ActionRef object
}Syntax errors: Invalid JSON or CSV syntax generates errors.
// Error: JSON syntax error
{
"id": "backup-job"
"action": {...} // Missing comma
}How seed data is deployed
The C3 Agentic AI Platform deploys seed data through database operations that create, update, or preserve records based on deployment rules and user permissions.
Deployment timing and process
The C3 Agentic AI Platform deploys seed data during package provisioning using the upsertAllSeed() operation.
Initial deployment: When you provision a package, it:
- Checks if the package fingerprint has changed since last deployment
- If changed, collects all seed data files from
seed/**and/data/** - Deploys each instance to the database using upsert operations
- Validates constraints and runs custom
validateSeedData()methods - Updates the deployment state with fingerprint and any issues
Reprovisioning: When you reprovision a package, the C3 Agentic AI Platform:
- Compares the current package fingerprint with the stored fingerprint
- Deploys seed data only if the fingerprint changed or deployment never completed
- Preserves user-modified fields during deployment (see User permissions section)
- Updates or creates database records as needed
Example flow:
Package deployed -> fingerprint changed -> collect seed files ->
deploy to database -> validate -> update state -> seeded = trueUser permissions
The @seed annotation controls whether users can modify seed data after deployment. Learn more in the Ann.Seed.
Annotation parameters:
@seed(userUpdatable=true, userRemovable=true)
entity type ExampleType mixes SeedData<ExampleType> {
// Fields users can update
description: string
inactive: boolean
// Fields only system can update
action: !ActionRef
scheduleDef: CronSchedule
...
}Permission levels:
System-provided seed data (created by provisioner):
- Users cannot modify non-user-updatable fields
- Users can modify user-updatable fields if
userUpdatable=true - Users can hide records if
userRemovable=true - System updates during reprovisioning do not overwrite user changes
User-created seed data (created by regular users):
- Users have full permission to modify their own records
- System updates do not affect user-created records
Field-level permissions:
By default, all fields are non-user-updatable for system seed data. To allow user updates on specific fields, the Type implementation must specify which fields are user-updatable.
Example user update attempt:
// User tries to update non-user-updatable field
CronJob job = CronJob.forId("backup-database");
job.withAction(newAction).upsert();
// Error: "Seed Data value can not be updated for field 'action' in type 'CronJob'"
// User successfully updates user-updatable field
job.withDescription("Updated description").upsert();
// Success: Field is marked as user-updatablePreserving user changes
The C3 Agentic AI Platform preserves user modifications during reprovisioning to prevent system updates from overwriting user customizations.
Preservation rules:
- User-modified fields: System updates during reprovisioning ignore fields in
userUpdatedFields - Non-modified fields: System updates during reprovisioning update non-modified fields
- Hidden records: System updates preserve the
hiddenstatus during reprovisioning
Example scenario:
Initial deployment:
CronJob id="backup-database", description="Backup database", inactive=false
User modification:
User updates: description="Backup production database"
userUpdatedFields: ["description"]
Reprovisioning:
Seed file changes: description="Backup database daily", inactive=true
System updates: inactive=true (not in userUpdatedFields)
System ignores: description (in userUpdatedFields)
Final state:
description="Backup production database" (preserved)
inactive=true (updated)
userUpdatedFields: ["description"]Clearing user changes:
Administrators can reset user modifications using clearUserUpdates():
CronJob job = CronJob.forId("backup-database");
job.clearUserUpdates(); // Clears userUpdatedFields
// Next reprovisioning will update all fieldsRuntime operations
The C3 Agentic AI Platform provides APIs for accessing, modifying, and removing seed data instances in the database.
Accessing instances
Retrieve instances from the database using standard entity methods.
// Access by id
CronJob job = CronJob.forId("backup-database");
// Fetch with filters
FetchSpec spec = FetchSpec.make()
.withFilter("inactive == false");
FetchResult<CronJob> jobs = CronJob.fetch(spec);
// Include hidden records (admin only)
FetchSpec adminSpec = FetchSpec.make()
.withFetchHiddenSeedData(true);
FetchResult<CronJob> allJobs = CronJob.fetch(adminSpec);Creating instances
Users can create new seed data instances if the Type allows user creation.
// Create new instance
CronJob newJob = CronJob.make()
.withId("custom-job")
.withName("Custom Job")
.withDescription("User-created job")
.withAction(action)
.withScheduleDef(schedule)
.upsert();For system provisioning, use createSeedData() to create instances as the root user:
CronJob systemJob = CronJob.make()
.withId("system-job")
.withName("System Job")
.withAction(action)
.withScheduleDef(schedule)
.createSeedData();
// meta.createdBy = "root"Updating instances
Update instances using upsert() or update() methods, subject to permission rules.
// User update (restricted by permissions)
CronJob job = CronJob.forId("backup-database");
job.withDescription("Updated description")
.upsert(); // Success: description is user-updatable
// System update (bypasses user restrictions)
job.withAction(newAction)
.updateSeedData(); // Updates only if field not in userUpdatedFieldsRemoving instances
Users can remove seed data instances based on the userRemovable permission.
Soft delete (user remove):
CronJob job = CronJob.forId("backup-database");
job.remove(); // Sets hidden=true, record remains in database
// Admin can see hidden records
FetchSpec spec = FetchSpec.make().withFetchHiddenSeedData(true);
CronJob hiddenJob = CronJob.fetch(spec).first(); // Returns hidden record
// Unremove restores visibility
hiddenJob.unremove(); // Sets hidden=falseHard delete (permanent remove):
CronJob job = CronJob.forId("backup-database");
job.removeSeedData(); // Permanently deletes from databasePermission rules:
- Users can soft delete if
userRemovable=true - Users cannot soft delete system seed data if
userRemovable=false - Only administrators can hard delete using
removeSeedData() - Soft deleted records preserve during reprovisioning