Project Structure

A MALV project has a specific directory structure. Understanding it helps you navigate and organize your code.

Overview

my-project/
├── malv.json              # Project configuration
├── malv.lock              # Lock file (version pinning)
├── package.json           # Node.js package config
├── .malv/                 # Local runtime data (gitignored)
├── malv_systems/          # Downloaded registry apps
└── packages/
    ├── apps/              # Your app source code
    │   ├── auth/
    │   ├── notes/
    │   └── email/
    └── web/               # Web interfaces

Project Root

malv.json

The main configuration file. Defines which apps to run and where to find them.

{
  "apps": {
    "@my-org/auth": "workspace:*",
    "@my-org/notes": "workspace:*"
  },
  "web": ["packages/web"]
}

See Configuration for full documentation.

malv.lock

Created by malv install. Records exact versions of installed registry apps for reproducible builds.

{
  "lockfileVersion": 1,
  "systems": {
    "@malv/gmail": {
      "version": "1.2.3",
      "integrity": "sha256-..."
    }
  }
}

Commit this file to version control.

The .malv Directory

Runtime data for local development. Always gitignored.

.malv/
├── dev/                   # Development environment files
│   ├── .env.auth          # Env vars for @my-org/auth
│   ├── .env.notes         # Env vars for @my-org/notes
│   └── .env.email         # Env vars for @my-org/email
├── production/            # Production environment files
│   ├── .env.auth
│   └── .env.notes
├── running-apps.json      # Registry of running apps (health checks)
└── dev-logs.jsonl         # Shared log file

Environment Files

Each app has its own .env file for secrets:

# .malv/dev/.env.auth
GOOGLE_CLIENT_ID=abc123
GOOGLE_CLIENT_SECRET=secret456

Configure with malv env. Never commit these files.

Log Files

View with malv logs.

The malv_systems Directory

Downloaded registry apps live here:

malv_systems/
├── @malv-gmail/           # @malv/gmail (slash → dash in folder name)
│   ├── package.json
│   ├── tools.json
│   ├── tokens.json
│   ├── storage.json
│   └── dist/
│       └── tools/
├── @malv-calendar/
└── .tmp/                  # Temporary directory for atomic installs

Workspace Integration

Add to your package.json workspaces for dependency installation:

{
  "workspaces": ["packages/*", "malv_systems/*"]
}

Then yarn install will install dependencies for downloaded apps.

App Structure

Each app follows a consistent structure:

packages/apps/notes/
├── package.json           # App metadata
├── tools.json             # Tool definitions
├── tokens.json            # Token definitions (optional)
├── storage.json           # Storage permissions (optional)
├── objects.json           # Object definitions (optional)
├── events.json            # Event definitions (optional)
├── environment.json       # Required env vars (optional)
├── rollup.config.js       # Build configuration
├── tsconfig.json          # TypeScript config
├── src/
│   ├── tools/             # Tool implementations
│   │   ├── create_note.ts
│   │   ├── edit_note.ts
│   │   └── list_notes.ts
│   └── types/             # Generated types (don't edit)
│       ├── TokenPayloads.ts
│       └── Environment.ts
├── dist/                  # Build output
│   └── tools/
│       ├── create_note.js
│       └── create_note.d.ts
├── objects/               # Object renderers (optional)
│   └── note/
│       ├── web.tsx
│       └── icon.svg
└── embeddings/            # Semantic search data (optional)

Configuration Files

File Purpose
tools.json Define available tools
tokens.json Define tokens this app issues
storage.json Declare storage permissions
objects.json Define visual objects
events.json Define event handlers
environment.json Declare required env vars

Source Code

Tool implementations live in src/tools/. Each file exports a default async function:

// src/tools/create_note.ts
export default async function create_note(
  input: Input,
  capabilities: Capabilities
): Promise<Output> {
  // Implementation
}

Generated Files

The src/types/ directory contains generated TypeScript types. Don't edit these - they're regenerated by malv generate and malv build.

Build Output

The dist/ directory contains built JavaScript. Required for publishing.

User Directory

Global CLI data lives in ~/.malv/:

~/.malv/
├── auth.json              # Authentication token
├── ai-config.json         # AI API key configuration
├── update-config.json     # Auto-update preferences
├── update-check.json      # Cached update check results
├── dev-logs.jsonl         # Global dev logs
└── infra-logs.jsonl       # Infrastructure logs

auth.json

Your registry authentication token. Created by malv login.

ai-config.json

AI API key for semantic search and summaries. Created by malv ai set.

{
  "provider": "openai",
  "apiKey": "sk-..."
}

Recommended .gitignore

# MALV
.malv/
malv_systems/
dist/

# Node
node_modules/

# Generated types (optional - some teams commit these)
src/types/

Related