Build a Project

A complete agent-run path from a product idea or repository to a running application.

Use this page when an agent is building a product, rather than only deploying a repository that is already prepared. It gives the decisions in the order they matter. The agent performs the MCP calls; a person makes the decisions that spend money, expose a domain they own, or disclose a value they do not want in the conversation.

A Project is the product. A Service is one deployable part inside it: a web application, API, worker, or another container with its own build, runtime, and Aidrop address. A Project may contain several Services, while its secrets and backing services remain within that Project. Start every session by reading projects_list, services_list, and repositories_list; they establish what already exists before anything new is made.

1. Choose the shape before writing code

Decide which parts deploy independently. A browser application, API, and background worker are separate Services even when they live in one repository: each one runs one container, listens on one port, and has its own build, settings, and address. They may still share a Project, secrets, and backing services.

Product shape Project and Service shape
A landing page or a small HTTP application One Project, one Service
Browser application plus API One Project, two Services
Monorepo with an API and worker One Project, one Service for each process that must run independently
Separate customer products One Project per product; Project resources never cross that boundary

If the application keeps records, sessions, queued work, or anything that must survive a restart, plan its backing service before writing files. An application has no persistent disk: its root filesystem is read-only and only /tmp, /run, and /var/tmp are writable scratch space. Do not use a file as a database, queue, upload store, or cache that must survive.

Read Runtime before choosing a stack. It says which resource classes and backing services the Team’s plan includes, and the runtime_envelope returned by service_get records the constraints of an existing Service. An application can reach the public internet only through the supplied HTTP proxy on ports 80 and 443. Use proxy-aware HTTPS clients for external APIs; a public database’s native port or SMTP is not reachable.

2. Create or select the Project

Use an existing Project when the work is another deployable part of the same product. Otherwise call project_create with the product’s name and description. The result’s project_id is the boundary for every following operation: Service builds, Project values, and backing services use that id.

Do not create a Service as a separate preparatory step. The first service_build creates it, links its repository, and records its initial runtime settings in one operation.

3. Put the code in a repository

There are two source routes:

  1. Existing GitHub code. A person installs the Aidrop GitHub App in the repository’s GitHub account. The repository then appears in repositories_list; use its repository_ref. The agent cannot install the App or supply GitHub credentials.
  2. New code or a local working tree. Call repository_create with the selected project_id. It returns an empty Team repository, clone URL, and push credential. An agent with a local shell writes the code, commits it, and pushes it with git. A chat-only client cannot move local files or push an archive; it can only build code that is already in a repository.

Before linking a repository, read repositories_list. It shows whether it already backs a Service in the selected Project. Reuse that Service when it is the same deployable; use a second Service only when the repository truly contains another process that must run separately.

The tracked branch is explicit. A Team repository starts on main; an imported repository starts on its existing default branch. Pass branch to the first build when another branch should be deployed, then push subsequent changes to that branch.

4. Decide how the Service runs

The platform does not infer the runtime settings from a repository. The agent must read the code and pass the answers to service_build:

Setting Decision
container_port Required on the first build. The port the process listens on inside the container. The application must bind the PORT it receives.
health_path The HTTP path that must answer successfully after start-up; / by default.
resource_class CPU and memory envelope. If omitted, the smallest class in the plan is used.
runtime_kind container by default, or a named runtime whose scaffold and constraints are returned in runtime_envelope.
build_type nixpacks by default, or dockerfile.
build_dockerfile_path Required with build_type: dockerfile; a path such as Dockerfile or build/Dockerfile.api, relative to the repository root.
required_secret_names Exact names of the Project values this Service receives at run time.

Nixpacks can build a repository without a Dockerfile, but it is an inference. For a repeatable build, commit a Dockerfile and explicitly pass both build_type: dockerfile and build_dockerfile_path. A Dockerfile that is present but not named is never used. The repository root is the build context, even when the Dockerfile lives in a subdirectory.

5. Add data and runtime values only when the code needs them

Use shared_resources_list for the current Project before creating a backing service. A PostgreSQL instance, cache, or queue belongs to one Project and is available only to Services in it. If PostgreSQL already exists, create another database in that instance with shared_resource_create and its parent_resource_id; that database does not need confirmed, because the instance is the billed resource. Name the service_id that should use it in the call, or attach it afterwards with shared_resource_update. Do not create a second PostgreSQL instance. If it does not exist, creating the first instance requires the user’s explicit confirmed decision because it is billed.

Attaching a database returns its connection string and environment-variable name, but does not save either one. Store the returned connection string with project_secret_set for the same Project, then include that variable in the Service’s required_secret_names on the next build. A Service receives only the values it names; another Project’s values and resources are never delivered to it.

For a third-party value such as a payment or mail API key, the same rule applies: store it as a Project value and name it in required_secret_names. Use the dashboard’s Project Secrets page when the person does not want to pass a credential through an agent conversation. Stored values are never returned by a tool.

6. Build and wait for the result

The first build creates the Service and links the repository. A typical first call has this shape:

service_build(
project_id: "…",
name: "web",
repository_ref: "team/product",
container_port: 3000,
health_path: "/health",
build_type: "dockerfile",
build_dockerfile_path: "Dockerfile",
required_secret_names: ["DATABASE_URL"]
)

Use the values that fit the actual repository; the example is not a template to copy unchanged. Later builds pass service_id and retain previous settings unless a setting is supplied again.

The build is queued and takes minutes. Poll service_get until the build succeeds or stops; its next_step says what follows from the current state. If it stops, read service_logs, fix the code or settings, commit and push to the tracked branch, then call service_build again. Do not treat a successful image build as a successful deployment: the application must also answer on its configured port and health path.

7. Verify, operate, and leave a clear next step

The first successful deployment creates the Service address. It is public on the internet immediately; add authentication to the application itself when visitors must sign in. service_get returns the address and current build, repository, runtime settings, and runtime envelope.

For a custom domain, call service_domain_add, create the one DNS record it returns, then call service_domain_verify with the returned domain_id. The DNS record is a person-owned step; do not guess a target from another Service.

Every successful build has an image tag. service_tags_list lists the tags, and service_start with an earlier tag rolls code back without rebuilding. Poll service_get until that image reports running. It does not roll database schema back, so make migrations forward-compatible. service_stop pauses an application; service_start without a tag resumes its current image.

Keep the continuation record with the code: document local commands, required values by name, migrations, service boundaries, and deployment decisions in the repository’s CLAUDE.md or equivalent. The next agent starts by reading the repository and the current Project, Service, and build records rather than guessing from an earlier chat.

Search the docs