> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs-shaunak-branch.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Creating Packages

> Where to put your files in C3 AI packages.

C3 AI packages use directory structure as a mechanism to activate platform features. Each directory serves a specific purpose, triggering different automations when files are placed in the correct locations.

This guide explains the standard package structure, what each directory does, and how the platform processes files based on their location.

## Getting started

### Package manifest

The manifest file is the only required component of a C3 AI package. At its most minimal, a valid package consists of just a single JSON file:

```bash
myPackage/
  myPackage.c3pkg.json    # Required manifest file
```

```json myPackage.c3pkg.json
{
  "name": "myPackage",        // Must match directory name
  "description": "My first package",
  "author": "C3 AI",
  "version": "1.0.0",        // Semantic versioning
  "dependencies": {}         // Other packages you depend on
}
```

The manifest contains essential metadata about your package:

* **name**: Must match the directory name exactly
* **description**: Brief explanation of the package's purpose
* **author**: Individual or organization that created the package
* **version**: Follows semantic versioning (MAJOR.MINOR.PATCH)
* **dependencies**: Other packages required by this package

For more details on dependencies and how to use existing packages, see the [Importing Packages](/platform-architecture/package-management/importing-a-package) guide.

### Adding source code and tests

While a manifest is enough for a valid package, you'll want to add code to make it useful. The platform automatically validates and connects your Types, implementations, and tests based on where you place them:

```bash
simpleAnalytics/
  src/                          # Source code directory
    Analytics.c3typ            # Type definition
    Analytics.js               # Implementation
  test/                        # Test directory
    Analytics.test.js          # Test file
  simpleAnalytics.c3pkg.json   # Package manifest
```

Here's how these files work together:

1. Define your interface in `Analytics.c3typ`:

```typescript
// Analytics.c3typ - Define the analytics capabilities
type Analytics {
  // Fields (properties of the Analytics type)
  name: string;
  description: string;
  
  // Method signature that will be implemented in Analytics.js
  analyzeData(data: array<number>): {
    mean: number;
    median: number;
    min: number;
    max: number;
  };
}
```

2. Implement the interface in `Analytics.js`:

```javascript
// Analytics.js - Implement the analytics functionality
Analytics.prototype.analyzeData = function(data) {
  // Sort the data once for multiple operations
  const sortedData = [...data].sort((a, b) => a - b);
  
  return {
    mean: data.reduce((sum, value) => sum + value, 0) / data.length,
    median: sortedData[Math.floor(sortedData.length / 2)],
    min: sortedData[0],
    max: sortedData[sortedData.length - 1]
  };
};
```

3. Verify it with tests in `Analytics.test.js`:

```javascript
// Analytics.test.js - Test the analytics functionality
describe('Analytics', () => {
  it('calculates statistics correctly for ordered data', () => {
    // Create a new instance with required properties
    const analytics = new Analytics();
    analytics.name = 'Test Analytics';
    analytics.description = 'Analytics for testing';
    
    // Test with a simple ordered dataset
    const result = analytics.analyzeData([1, 2, 3, 4, 5]);
    
    // Verify all calculated statistics
    expect(result.mean).toBe(3);
    expect(result.median).toBe(3);
    expect(result.min).toBe(1);
    expect(result.max).toBe(5);
  });
  
  it('calculates statistics correctly for unordered data', () => {
    const analytics = new Analytics();
    
    // Test with an unordered dataset
    const result = analytics.analyzeData([5, 1, 3, 2, 4]);
    
    // Verify all calculated statistics
    expect(result.mean).toBe(3);
    expect(result.median).toBe(3);
    expect(result.min).toBe(1);
    expect(result.max).toBe(5);
  });
});
```

## Building larger applications

### Application structure

As your package grows, you'll want to leverage more platform features. Here's how to organize a full application with business logic, UI components, and platform integrations:

```bash
reliabilityMonitor/
  src/                         # Application logic
    asset/                    # Domain-grouped files
      Asset.c3typ
      Asset.js
    sensor/
      Sensor.c3typ
      Sensor.js
  ui/                         # Frontend code
    components/
      AssetCard.jsx
    pages/
      Dashboard.jsx
  config/                     # Environment config
    AppConfig/
      settings.json
  metadata/                   # Platform integration
    Schedule/
      healthCheck.json
  seed/                      # Initial data
    Asset/
      defaultAssets.json
  data/                      # Reference data
    reference/
      equipment-codes.csv
  resource/                  # Static assets
    templates/
      alert-email.html
  test/                      # Tests
    src/
      asset/
        Asset.test.js
  reliabilityMonitor.c3pkg.json
```

### Optional components

Each directory in your package enables specific platform features:

<AccordionGroup>
  <Accordion title="Source Files (src/)">
    **Purpose**: Core application logic

    **Rules**:

    * Type files define interfaces (`.c3typ`)
    * Implementation files fulfill interfaces (`.js`, `.py`)
    * Names must match (example: `Asset.c3typ` → `Asset.js`)

    **Automations**:

    * Validates implementations against Types
    * Generates TypeScript definitions
    * Creates API documentation

    Here's how these rules work in the `src/` directory. For an Asset type:

    ```typescript
    // src/Asset.c3typ - Define the interface
    type Asset mixes Persistable {
      id: string;
      name: string;
      description: string;
      status: AssetStatus;
      sensors: array<Sensor>;  // Relationship to other Types
      
      // Methods that will be implemented in Asset.js
      getHealth(): number;
      updateStatus(status: AssetStatus): void;
    }
    ```

    For more details on Types, see the [C3 Type System](/platform-architecture/c3-type-system/overview) guide.
  </Accordion>

  <Accordion title="User Interface (ui/)">
    **Purpose**: Application frontend components and pages

    **Rules**:

    * **Components go in `components/`**: Reusable UI elements that can be composed into pages
      * Examples: Cards, panels, form elements, charts, tables
      * Should be focused on presentation and accept data via props
      * Should be reusable across multiple pages
    * **Full pages go in `pages/`**: Complete application views that combine components
      * Examples: Dashboards, detail views, settings screens
      * Typically fetch data and pass it to components
      * Correspond to routes in your application
    * Must use platform UI libraries for consistent styling and behavior

    **Automations**:

    * Bundles and optimizes code for production deployment
    * Automatically generates application routes from page files
    * Creates TypeScript bindings for type safety
    * Handles CSS/SCSS processing and optimization

    Let's look at examples of both a component and a page:

    **Component Example** (`ui/components/AssetCard.jsx`):

    ```jsx
    // A reusable card component for displaying assets
    // This can be used in multiple pages throughout the application
    function AssetCard({ asset, onStatusChange }) {
      return (
        <Card className="asset-card">
          <Heading level={3}>{asset.name}</Heading>
          <StatusIndicator 
            status={asset.status} 
            onChange={onStatusChange} 
          />
          <MetricDisplay 
            label="Health Score" 
            value={asset.healthScore} 
            unit="%" 
          />
        </Card>
      );
    }

    export default AssetCard;
    ```

    **Page Example** (`ui/pages/AssetDashboard.jsx`):

    ```jsx
    // A complete page that uses multiple components
    // This will automatically be available at the /assets route
    function AssetDashboard() {
      // Fetch data for the page
      const [assets, setAssets] = useState([]);
      
      useEffect(() => {
        // Load assets from the backend
        Asset.fetchAll().then(setAssets);
      }, []);
      
      // Handle status changes
      const handleStatusChange = (assetId, newStatus) => {
        Asset.updateStatus(assetId, newStatus);
      };
      
      return (
        <PageLayout title="Asset Dashboard">
          <FilterPanel onFilterChange={/* handler */} />
          
          <Grid columns={3}>
            {assets.map(asset => (
              <AssetCard 
                key={asset.id} 
                asset={asset} 
                onStatusChange={(status) => handleStatusChange(asset.id, status)}
              />
            ))}
          </Grid>
        </PageLayout>
      );
    }

    export default AssetDashboard;
    ```

    The platform will automatically bundle these files, create routes, and make components available to your pages.
  </Accordion>

  <Accordion title="Configuration (config/)">
    **Purpose**: Environment-specific settings that control application behavior without code changes

    **Rules**:

    * **Must be valid JSON or YAML**: Configuration must be in a supported format
      * JSON is the most common format
      * YAML is supported for more complex configurations
      * Comments are allowed in configuration files
    * **Values must match Type definitions**: Configuration should have a corresponding Type
      * Example: `config/AppConfig/settings.json` should match `AppConfig` Type
      * Type validation ensures configuration correctness
      * Prevents runtime errors from invalid configuration
    * **Use environment suffixes for environment-specific values**:
      * Base file: `config/AppConfig/settings.json` (default values)
      * Development: `config/AppConfig/settings.dev.json` (overrides for development)
      * Production: `config/AppConfig/settings.prod.json` (overrides for production)
      * Test: `config/AppConfig/settings.test.json` (overrides for testing)

    **Automations**:

    * **Loads correct values per environment**: Platform automatically selects the right configuration
      * Base values are loaded first
      * Environment-specific values override base values
      * Environment is determined by deployment context
    * **Validates against schemas**: Configuration is validated against Type definitions
      * Type checking prevents invalid values
      * Required fields are enforced
      * Validation happens at deployment time
    * **Makes settings available to code**: Configuration is accessible through the Configuration API
      * Use `Configuration.get('path.to.value')` to access values
      * Changes to configuration don't require code changes
      * Configuration can be updated without redeployment

    **Configuration Examples**:

    **Base Configuration** (`config/AppConfig/settings.json`):

    ```json
    {
      "monitoring": {
        "checkInterval": "5m",
        "alertThreshold": 90,
        "notificationChannels": ["email"],
        "retentionPeriod": "30d"
      },
      "ui": {
        "refreshInterval": "1m",
        "theme": "light",
        "defaultView": "dashboard"
      },
      "integration": {
        "externalApiUrl": "https://api.example.com",
        "timeout": "30s",
        "retryCount": 3
      }
    }
    ```

    **Production Override** (`config/AppConfig/settings.prod.json`):

    ```json
    {
      "monitoring": {
        "checkInterval": "1m",
        "notificationChannels": ["email", "sms", "slack"]
      },
      "integration": {
        "externalApiUrl": "https://api.production.example.com",
        "timeout": "10s"
      }
    }
    ```

    **Configuration Type Definition** (`src/config/AppConfig.c3typ`):

    ```typescript
    type AppConfig mixes Configuration {
      monitoring: {
        checkInterval: string;
        alertThreshold: number;
        notificationChannels: array<string>;
        retentionPeriod: string;
      };
      ui: {
        refreshInterval: string;
        theme: string;
        defaultView: string;
      };
      integration: {
        externalApiUrl: string;
        timeout: string;
        retryCount: number;
      };
    }
    ```

    **Accessing Configuration in Code**:

    ```javascript
    // Get a specific configuration value
    const threshold = Configuration.get('monitoring.alertThreshold');

    // Get a section of configuration
    const uiConfig = Configuration.get('ui');

    // Get configuration with environment-specific overrides
    const apiUrl = Configuration.get('integration.externalApiUrl');
    // In development: "https://api.example.com"
    // In production: "https://api.production.example.com"
    ```

    **When to use configuration**:

    * For settings that change between environments
    * For values that non-developers need to adjust
    * For feature flags and toggles
    * For connection strings and external service URLs
  </Accordion>

  <Accordion title="Metadata (metadata/)">
    **Purpose**: Platform integration points that define how your package interacts with the C3 AI Agentic Platform

    **Rules**:

    * **One subdirectory per integration type**: Each integration type has its own directory
      * Common integration types include:
        * `Schedule/`: Scheduled jobs and cron tasks
        * `Role/`: User roles and permissions
        * `Translation/`: Internationalization strings
        * `SimpleMetric/`: Metrics for monitoring
        * `CodeCoverageInstrumentationSpec/`: Test coverage configuration
    * **Must follow integration schemas**: Each integration type has a specific schema
      * Schemas are validated during deployment
      * Invalid schemas will cause deployment failures
    * **Changes require redeployment**: Metadata changes only take effect after redeployment
      * Unlike configuration, metadata can't be changed at runtime
      * Plan metadata changes carefully to minimize disruption

    **Automations**:

    * Registers scheduled jobs in the platform's job scheduler
    * Sets up permissions and access control for users
    * Configures metrics for monitoring and dashboards
    * Registers translations for internationalization

    Here are examples of common metadata types:

    **Scheduled Job Example** (`metadata/Schedule/HealthCheck.json`):

    ```json
    {
      "name": "HealthCheck",
      "description": "Daily health check for all assets",
      "cron": "0 0 * * *",  // Daily at midnight
      "method": "reliability.checkAssetHealth",
      "enabled": true,
      "parameters": {
        "thoroughScan": true,
        "notifyOnFailure": true
      },
      "timeout": "1h"
    }
    ```

    **Role Definition Example** (`metadata/Role/Operator.json`):

    ```json
    {
      "name": "Operator",
      "description": "Role for plant operators",
      "permissions": [
        "asset:read",
        "asset:update",
        "alert:read",
        "alert:acknowledge"
      ],
      "extends": ["BaseUser"]
    }
    ```

    **Translation Example** (`metadata/Translation/en.csv`):

    ```csv
    id,locale,key,value
    alert.critical,en,alert.critical,Critical Alert
    alert.warning,en,alert.warning,Warning
    alert.info,en,alert.info,Information
    ```

    When you deploy your package, the platform automatically processes these metadata files and configures the appropriate platform services.
  </Accordion>

  <Accordion title="Tests (test/)">
    **Purpose**: Automated testing to ensure code quality and prevent regressions

    **Rules**:

    * **Mirror source structure**: Tests should follow the same organization as your source code
      * Example: `src/asset/Asset.js` → `test/src/asset/Asset.test.js`
      * Makes it easy to find tests for specific components
      * Ensures complete test coverage across your codebase
    * **Names must match source files**: Test files should have the same name as the source file with a `.test` suffix
      * Example: `Asset.js` → `Asset.test.js`
      * Enables automatic test discovery
      * Makes it clear what each test file is testing
    * **Required for production code**: All production code should have tests
      * Unit tests for individual functions and methods
      * Integration tests for interactions between components
      * End-to-end tests for complete workflows

    **Automations**:

    * **Discovers and runs tests**: Platform automatically finds and executes tests
      * No need to manually register tests
      * Tests run automatically during builds
      * Supports multiple test frameworks (Jest, Mocha, Pytest)
    * **Reports coverage**: Platform generates test coverage reports
      * Shows which code is tested and which isn't
      * Identifies untested code paths
      * Can enforce minimum coverage thresholds
    * **Integrates with CI/CD**: Tests run automatically in CI/CD pipelines
      * Prevents deployment of failing code
      * Provides feedback on test failures
      * Maintains code quality over time

    **Test Examples**:

    **Unit Test** (`test/src/asset/Asset.test.js`):

    ```javascript
    // Unit test for Asset.js
    describe('Asset', () => {
      // Test the getHealth method
      describe('getHealth', () => {
        it('returns the health score when available', () => {
          // Create a test asset with a known health score
          const asset = new Asset({
            id: 'test-asset',
            name: 'Test Asset',
            healthScore: 85
          });
          
          // Verify the method returns the expected value
          expect(asset.getHealth()).toBe(85);
        });
      });
      
    });
    ```

    **Integration Test** (`test/integration/AssetSensor.test.js`):

    ```javascript
    // Integration test for Asset and Sensor interaction
    describe('Asset and Sensor Integration', () => {
      it('updates asset health when sensor readings change', async () => {
        // Create test data
        const asset = await Asset.create({
          id: 'test-asset',
          name: 'Test Asset'
        });
        
        const sensor = await Sensor.create({
          id: 'test-sensor',
          name: 'Test Sensor',
          asset: asset.id,
          reading: 75
        });
        
        // Trigger the event that should update the asset
        await sensor.updateReading(90);
        
        // Reload the asset to get the latest data
        const updatedAsset = await Asset.fetch(asset.id);
        
        // Verify the asset health was updated based on the sensor
        expect(updatedAsset.healthScore).toBe(90);
      });
    });
    ```

    **When to write tests**:

    * Before writing implementation code (Test-Driven Development)
    * When adding new features
    * When fixing bugs (to prevent regressions)
    * When refactoring code (to ensure behavior doesn't change)
  </Accordion>

  <Accordion title="Seed Data (seed/)">
    **Purpose**: Initial data loaded during first deployment to populate your application with starter content

    **Rules**:

    * **Must match Type definitions**: Seed data must conform to your Type schemas
      * Field names and types must match your Type definitions
      * Required fields must be present
      * Relationships between entities must be valid
    * **One subdirectory per entity Type**: Organize seed data by the Type it populates
      * Example: `seed/Asset/` for Asset instances
      * Example: `seed/User/` for User instances
    * **JSON or CSV format**: Data must be in a supported format
      * JSON is preferred for complex objects with nested structures
      * CSV is useful for simple tabular data

    **Automations**:

    * **Automatic loading during first deployment**: Data is loaded when the package is first deployed
      * No manual data entry required to get started
      * Creates a consistent starting state
    * **Data validation against Types**: Platform validates data against Type definitions
      * Invalid data will cause deployment failures
      * Ensures data integrity from the start
    * **Preservation across updates**: Seed data is only loaded once
      * Subsequent deployments won't overwrite existing data
      * Safe to modify seeded data after deployment

    **Seed Data Example** (`seed/Asset/InitialAssets.json`):

    ```json
    [
      {
        "id": "asset-001",
        "name": "Main Turbine",
        "description": "Primary power generation turbine",
        "status": "ACTIVE",
        "healthScore": 100,
        "installDate": "2023-01-15",
        "location": {
          "facility": "Plant A",
          "area": "Generation Hall",
          "coordinates": {
            "latitude": 37.7749,
            "longitude": -122.4194
          }
        },
        "sensors": ["sensor-001", "sensor-002", "sensor-003"]
      },
      {
        "id": "asset-002",
        "name": "Backup Generator",
        "description": "Emergency backup power generator",
        "status": "STANDBY",
        "healthScore": 95,
        "installDate": "2023-02-20",
        "location": {
          "facility": "Plant A",
          "area": "Auxiliary Building",
          "coordinates": {
            "latitude": 37.7750,
            "longitude": -122.4195
          }
        },
        "sensors": ["sensor-004", "sensor-005"]
      }
    ]
    ```

    **When to use seed data**:

    * To provide default configuration values
    * To populate lookup tables and reference data
    * To create demo or sample content for testing
    * To establish initial user roles and permissions
  </Accordion>

  <Accordion title="Reference Data (data/)">
    **Purpose**: Static reference data, lookup tables, and other non-persistent data used by your application

    **Rules**:

    * **Standard formats (CSV, JSON)**: Use widely supported formats
      * CSV for simple tabular data
      * JSON for structured data
      * YAML for configuration-like data
    * **Organized by data type**: Group related data together
      * Example: `data/reference/` for lookup tables
      * Example: `data/validation/` for validation rules
      * Example: `data/ml/` for machine learning parameters
    * **Must include schema validation**: Define the structure of your data
      * Include schema files when possible
      * Document data format in comments
      * Ensure consistent structure across files

    **Automations**:

    * **Automatic loading and validation**: Data is loaded at runtime
      * Available to your code through the Data API
      * Validated against schemas when loaded
    * **Runtime access to data**: Access data programmatically
      * Query and filter data in memory
      * Join with other data sources
      * Cache for performance
    * **Version tracking**: Data is versioned with your package
      * Changes are tracked in source control
      * Updates deploy with your package

    **Reference Data Examples**:

    **Equipment Codes** (`data/reference/equipment-codes.csv`):

    ```csv
    code,description,category,manufacturer,lifecycle_years
    TRB-001,Main Turbine,TURBINE,General Electric,25
    GEN-001,Primary Generator,GENERATOR,Siemens,20
    PMP-001,Cooling Pump,PUMP,Flowserve,15
    VLV-001,Control Valve,VALVE,Emerson,10
    MTR-001,Electric Motor,MOTOR,ABB,15
    ```

    **Status Mappings** (`data/reference/status-mappings.json`):

    ```json
    {
      "statusMappings": {
        "ACTIVE": {
          "displayName": "Active",
          "color": "#4CAF50",
          "priority": 1,
          "allowedTransitions": ["MAINTENANCE", "STANDBY", "FAILED"]
        },
        "STANDBY": {
          "displayName": "Standby",
          "color": "#2196F3",
          "priority": 2,
          "allowedTransitions": ["ACTIVE", "MAINTENANCE"]
        },
        "MAINTENANCE": {
          "displayName": "Under Maintenance",
          "color": "#FFC107",
          "priority": 3,
          "allowedTransitions": ["ACTIVE", "STANDBY", "FAILED"]
        },
        "FAILED": {
          "displayName": "Failed",
          "color": "#F44336",
          "priority": 4,
          "allowedTransitions": ["MAINTENANCE"]
        }
      }
    }
    ```

    **When to use reference data**:

    * For lookup tables that rarely change
    * For mapping and translation tables
    * For configuration parameters that aren't environment-specific
    * For validation rules and constraints
  </Accordion>
</AccordionGroup>

## Package organization strategies

### Single vs multiple packages

As your application grows, you'll need to make strategic decisions about package organization. Here are concrete guidelines for when to use each approach:

#### Single Package Approach

Start with a single package for small teams (1-5 developers) working on applications with fewer than 50 Types. This works especially well for early-stage projects where you need flexibility to evolve your design. You'll benefit from simpler dependency management, quicker refactoring across component boundaries, and faster development cycles since everything lives in one place.

**Example Structure**:

```bash
reliabilityMonitor/
  src/                      # Core application logic
    asset/                 # Asset domain
      Asset.c3typ         # Asset Type definition
      Asset.js            # Asset implementation
      AssetService.js     # Asset-specific business logic
    sensor/               # Sensor domain
      Sensor.c3typ
      Sensor.js
      SensorService.js
    alert/                # Alert domain
      Alert.c3typ
      Alert.js
      AlertService.js
    common/               # Shared utilities
      DateUtils.js
      FormatUtils.js
  ui/                      # Frontend code
    components/           # Reusable UI components
      AssetCard.jsx
      SensorDisplay.jsx
      AlertBadge.jsx
    pages/                # Full application pages
      Dashboard.jsx
      AssetDetails.jsx
      Settings.jsx
  config/                  # Configuration
    AppConfig/
      settings.json
  metadata/                # Platform integration
    Schedule/
      dailyHealthCheck.json
    Role/
      Operator.json
      Administrator.json
  reliabilityMonitor.c3pkg.json
```

**Real-world example**: The `reliabilityDataModel` package in our reliability examples uses a single package approach because it focuses on a set of data models that are tightly coupled.

#### Multiple Package Approach

As your application grows beyond 50 Types or your team expands past 5 developers, you'll want to consider splitting into multiple packages. This approach helps for mature applications where you've clearly defined component boundaries. Breaking things up creates clear ownership lines, lets teams version components independently, enables reuse across projects, and reduces merge conflicts when multiple developers work in parallel.

**Example Structure**:

```bash
# Core domain models and business logic
reliability-core/
  src/
    asset/
    sensor/
    alert/
  config/
  metadata/
  reliability-core.c3pkg.json

# UI components and pages
reliability-ui/
  src/
    components/
    pages/
    themes/
  reliability-ui.c3pkg.json  # Depends on reliability-core

# Analytics and reporting
reliability-analytics/
  src/
    reports/
    metrics/
    predictions/
  reliability-analytics.c3pkg.json  # Depends on reliability-core

# Main application that ties everything together
reliability-app/
  src/
    app/
  config/
  reliability-app.c3pkg.json  # Depends on all other packages
```

**Real-world example**: The reliability examples in our platform use multiple packages (`reliabilityDataModel`, `reliabilityMl`, `reliabilityUiComponentLibrary`) because each focuses on a different aspect of the application that can evolve independently.

### When to split packages

You'll recognize when to split your package as natural boundaries emerge in your codebase:

**Functional boundaries** appear when you see distinct groups forming in your code. For example, we separated data models from ML components in the reliability examples because they serve different purposes and evolve independently. This separation lets specialists focus on their domain without affecting other areas.

```
Before:                After:
myApp/                 myApp-dataModel/    
  src/                   src/
    dataModel/             Asset.c3typ
    analytics/          myApp-analytics/
    ui/                   src/
                        myApp-ui/
```

**Team boundaries** matter when multiple teams contribute to your codebase. Giving each team their own package reduces coordination overhead and prevents merge conflicts, letting teams work at their own pace.

**Reuse potential** signals the need to extract shared components. We created `reliabilityUiComponentLibrary` to share UI components across applications, reducing duplication and ensuring consistent user experiences.

**Versioning needs** differ across components. Your data models might stabilize early while your UI evolves rapidly. Separating these components lets you version them independently, using minor bumps for stable components and major updates for rapidly changing ones.

## Next steps

<CardGroup cols={2}>
  <Card title="Set Up Your Environment" href="/create-a-base-app/project-setup/setting-up-local-dev-environment">
    Create your first package and start developing
  </Card>

  <Card title="Import Packages" href="/platform-architecture/package-management/importing-a-package">
    Use existing packages in your application
  </Card>

  <Card title="Manage Artifacts" href="/platform-architecture/package-management/artifact-management">
    Version and distribute your packages
  </Card>
</CardGroup>
