---
title: "AtlasCloud: Add Models & Nodes"
description: "How to add a new AtlasCloud model or node to NodeTool by editing the manifest and rebuilding."
canonical: https://docs.nodetool.ai/developer/providers/atlascloud
markdown: https://docs.nodetool.ai/developer/providers/atlascloud.md
product: NodeTool
source: https://github.com/nodetool-ai/nodetool/blob/main/docs/developer/providers/atlascloud.md
---

# AtlasCloud: Add Models & Nodes

**Navigation**: [Developer Index](../index.md) | [Providers Overview](../../providers.md) → **AtlasCloud**

> **Audience**: contributors and coding agents adding AtlasCloud models or node classes. No familiarity with the runtime internals is assumed; you need to edit JSON and run two commands.

## TL;DR

1. Add an entry to `packages/atlascloud-nodes/src/atlascloud-manifest.json`.
2. Run `npm run build:packages` to copy the manifest into `dist/`.
3. Run `npm run typecheck && npm run test --workspace=packages/atlascloud-nodes`.

That's it. No TypeScript code is required for most new models. Skip to [Add a new model/node](#add-a-new-modelnode) for the exact steps.

---

## Where things live

| What | Path |
|---|---|
| Manifest (hand-maintained JSON, single source of truth) | `packages/atlascloud-nodes/src/atlascloud-manifest.json` |
| Manifest copy in `dist/` (generated by build) | `packages/atlascloud-nodes/dist/atlascloud-manifest.json` |
| Node class factory (reads manifest at runtime) | `packages/atlascloud-nodes/src/atlascloud-factory.ts` |
| HTTP helpers, poll/submit/download | `packages/atlascloud-nodes/src/atlascloud-base.ts` |
| Package entry point (exports `ATLASCLOUD_NODES`) | `packages/atlascloud-nodes/src/index.ts` |
| Runtime provider (image/video model lists, textToImage etc.) | `packages/runtime/src/providers/atlascloud-provider.ts` |
| Provider registration | `packages/runtime/src/providers/index.ts` line 222 |
| Manifest-to-model-list helper (shared with KIE, FAL) | `packages/runtime/src/providers/manifest-models.ts` |

---

## How AtlasCloud models/nodes are defined

There is no codegen script. `atlascloud-manifest.json` is hand-maintained. It is the single file you edit to add a model.

### Manifest → node class

`packages/atlascloud-nodes/src/index.ts` reads the manifest with `readFileSync` at module load time and passes it to `loadAtlasNodesFromManifest`. That function calls `createAtlasNodeClass` once per manifest entry. `createAtlasNodeClass` (in `atlascloud-factory.ts`) produces a `BaseNode` subclass whose `nodeType` is `atlascloud.<moduleName>.<className>`, whose input props match the `fields` array, and whose `process()` method calls `atlasSubmit → atlasPoll → atlasDownload`.

The `build` script in `package.json` compiles TypeScript then copies `src/atlascloud-manifest.json` to `dist/`:

```json
"build": "node ../../scripts/build-typescript-workspace.mjs && node -e \"require('node:fs').cpSync('src/atlascloud-manifest.json', 'dist/atlascloud-manifest.json')\""
```

The manifest export declared in `package.json` is:

```json
"./atlascloud-manifest.json": "./dist/atlascloud-manifest.json"
```

### Manifest → model list (provider)

`AtlasCloudProvider.getAvailableImageModels()` and `getAvailableVideoModels()` call `loadImageModels` / `loadVideoModels` from `manifest-models.ts`, which `require`s the manifest via `@nodetool-ai/atlascloud-nodes/atlascloud-manifest.json`. The model-list functions read `outputType`, `modelId`, and `title` from each entry. `buildModelMap()` in the provider reads the same manifest to know which fields each model accepts for the generic `textToImage` / `imageToVideo` etc. methods.

**Key point**: the manifest drives both the node UI (fields, defaults, enum values) and the model picker (image/video model lists). Editing the manifest is sufficient for both.

### Wire protocol

- Submit: `POST https://api.atlascloud.ai/api/v1/model/generateImage` or `.../generateVideo`
- Body: flat JSON — `{ model: "<modelId>", ...fields }` (not nested under `input`)
- Poll: `GET https://api.atlascloud.ai/api/v1/model/prediction/<id>`
- Terminal statuses: `completed`, `succeeded`, `success`, `done`, `complete`, `canceled`, `failed`, `error`
- Submit is **never retried** — a 5xx may have already created and billed the job upstream.

---

## Add a new model/node

### Step 1: Identify the model

From the AtlasCloud docs or API, collect:

- The model id string, e.g. `"bytedance/seedance-3.0/text-to-video"`
- The modality: `"image"` or `"video"`
- The field names and types the endpoint accepts

### Step 2: Choose a `className` and `moduleName`

- `className`: PascalCase identifier used as the TypeScript class name and the last segment of the node type. Example: `"Seedance3TextToVideo"`.
- `moduleName`: one of `"image"` or `"video"` (matches the output type). Used in the node type: `atlascloud.video.Seedance3TextToVideo`.

### Step 3: Append an entry to the manifest

Open `packages/atlascloud-nodes/src/atlascloud-manifest.json`. Append an object following this shape (copy the closest existing entry and adjust):

```json
{
  "className": "Seedance3TextToVideo",
  "moduleName": "video",
  "modality": "video",
  "modelId": "bytedance/seedance-3.0/text-to-video",
  "outputType": "video",
  "title": "Seedance 3.0 — Text to Video",
  "description": "AtlasCloud / ByteDance Seedance 3.0 — text-to-video with native audio.",
  "pollInterval": 5000,
  "maxAttempts": 600,
  "fields": [
    {
      "name": "prompt",
      "type": "str",
      "default": "",
      "title": "Prompt",
      "description": "Text prompt describing the desired video.",
      "required": true
    },
    {
      "name": "duration",
      "type": "int",
      "default": 5,
      "title": "Duration (seconds)",
      "values": [-1, 4, 5, 6, 7, 8, 9, 10]
    },
    {
      "name": "resolution",
      "type": "enum",
      "default": "720p",
      "title": "Resolution",
      "values": ["480p", "720p", "1080p"]
    },
    {
      "name": "ratio",
      "type": "enum",
      "default": "16:9",
      "title": "Aspect Ratio",
      "values": ["16:9", "9:16", "1:1", "adaptive"]
    }
  ]
}
```

**Field type reference**:

| `type` | Description |
|---|---|
| `"str"` | Text input |
| `"int"` | Integer (coerced from string dropdowns) |
| `"float"` | Float |
| `"bool"` | Checkbox |
| `"enum"` | Dropdown; requires `"values"` array |
| `"image"` | Single image ref |
| `"video"` | Single video ref |
| `"audio"` | Single audio ref |
| `"list[image]"` | Multiple image refs |
| `"list[video]"` | Multiple video refs |
| `"list[audio]"` | Multiple audio refs |

Use `"list[image]"` (not `image` with `"array": true`) for multi-image inputs. Use `"null"` as the default for optional enum fields without a sensible preselected value (e.g. `aspect_ratio` on Nano Banana models).

**`pollInterval`**: milliseconds between poll requests. Use 3000 for image models, 5000 for video models.

**`maxAttempts`**: maximum polls before timing out. 300 is reasonable for image; 600 for long-form video.

### Step 4: Build

```bash
npm run build:packages
```

This compiles TypeScript and copies the manifest into `dist/`. The factory picks it up at module load time — no TypeScript changes needed.

### Step 5: Smoke-test the node

```bash
ATLASCLOUD_API_KEY=<your_key> \
  npm run dev:nodetool -- node run \
  atlascloud.video.Seedance3TextToVideo \
  --props '{"prompt":"a red balloon floating upward","duration":5,"resolution":"720p","ratio":"16:9"}'
```

For a hermetic check (no secrets, no API call — verifies the node can be instantiated):

```bash
npm run dev:nodetool -- node run atlascloud.video.Seedance3TextToVideo \
  --props '{"prompt":"test"}' --no-secrets 2>&1 | grep -E "error|ATLASCLOUD"
```

Expected: `ATLASCLOUD_API_KEY is not configured` (meaning the node loaded and reached the key check).

### Step 6: Validate (no API call)

```bash
npm run dev:nodetool -- validate workflow.json
```

If you have a workflow JSON referencing the new node, this verifies the node type is registered and all edges type-check.

---

## Verify

Run these in order after any manifest change:

```bash
# 1. Rebuild (copies manifest to dist)
npm run build:packages

# 2. Type check the whole repo
npm run typecheck

# 3. Test atlascloud-nodes
npm run test --workspace=packages/atlascloud-nodes

# 4. Test runtime providers (checks manifest-models and the provider)
npm run test --workspace=packages/runtime

# 5. Full check (runs all three root-level checks)
npm run check
```

None of these make live API calls. Tests use vitest with mocked HTTP.

---

## How past PRs did it

The `atlascloud-nodes` package and `atlascloud-provider.ts` were introduced together in commit **`d1491abf`** ("add claude agent package"), which also added the entire file set:

```
packages/atlascloud-nodes/src/atlascloud-manifest.json   +1248 lines
packages/atlascloud-nodes/src/atlascloud-factory.ts       +637 lines
packages/atlascloud-nodes/src/atlascloud-base.ts          +220 lines
packages/atlascloud-nodes/src/index.ts                    +47 lines
packages/atlascloud-nodes/tests/...                       +1120 lines
packages/runtime/src/providers/atlascloud-provider.ts     +492 lines
```

The initial manifest shipped with 12 entries covering Seedance 2.0, Seedance 2.0 Fast, GPT Image 2, Nano Banana 2, and Nano Banana Pro. Each subsequent model addition follows the same pattern: one new JSON object in `atlascloud-manifest.json`, then `npm run build:packages`.

---

## Contributing

Source: <https://github.com/nodetool-ai/nodetool>  
Discord: <https://discord.gg/WmQTWZRcYE>

Before opening a PR, run `npm run check` (typecheck + lint + tests). The PR description should include the AtlasCloud model id, the node type string, and a brief note on which fields were included and why any fields from the API docs were omitted.
