autodisc
Project workspace

Set up your repository

Make an application portable to Autodisc with explicit runtime, network, health, database, and migration contracts.

Autodisc can detect common runtimes, but a production repository should make its deployment contract explicit. The important work is not “using the AI agent.” It is making the repository portable: one build, one start command, declared ports, environment-based dependencies, and a health signal.

This guide shows the same changes a developer can make by hand, in a pull request, without managed AI.

The repository contract

An Autodisc-ready service must:

  1. build without interactive input;
  2. start with one deterministic command;
  3. listen on 0.0.0.0 and the configured port;
  4. read credentials and environment-specific URLs from environment variables;
  5. expose a lightweight health endpoint when it serves HTTP;
  6. write logs to standard output and standard error;
  7. stop cleanly on SIGTERM; and
  8. keep database migrations separate from every replicated app process.

The same contract works locally, in CI, and on another container platform.

1. Make the server portable

Do not bind only to localhost, and do not hardcode a production port.

const port = Number(process.env.PORT ?? 3000);

const server = app.listen(port, "0.0.0.0", () => {
  console.log(`api listening on ${port}`);
});

process.on("SIGTERM", () => {
  server.close((error) => {
    process.exit(error ? 1 : 0);
  });
});

Add a health endpoint that proves the process can serve requests. Keep it fast and avoid mutating data.

app.get("/health", (_request, response) => {
  response.status(200).json({ status: "ok" });
});

A liveness endpoint should normally report process health. If you also need to check a database or queue, expose a separate readiness endpoint so a temporary dependency failure does not create a restart loop.

2. Move environment-specific values out of source

Commit variable names and safe local defaults. Do not commit credentials.

# .env.example
PORT=3000
DATABASE_URL=postgresql://user:password@localhost:5432/app
REDIS_URL=redis://localhost:6379/0
PUBLIC_APP_URL=http://localhost:3000

Application code should fail clearly when a required value is absent:

function required(name: string): string {
  const value = process.env[name];
  if (!value) throw new Error(`${name} is required`);
  return value;
}

const databaseUrl = required("DATABASE_URL");

In Autodisc, enter secret values in the selected environment's Variables settings. A staging value does not automatically become a production value.

3. Containerize deliberately

An explicit Dockerfile gives the repository one repeatable build definition. This Node example installs from the lockfile, creates a production build, and runs as a non-root user:

FROM node:24-bookworm-slim AS build
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM node:24-bookworm-slim AS runtime
ENV NODE_ENV=production
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev && npm cache clean --force
COPY --from=build /app/dist ./dist
USER node
EXPOSE 3000
CMD ["node", "dist/server.js"]

Also add a .dockerignore:

.git
.env
.env.*
!.env.example
node_modules
dist
coverage

Test the same artifact locally before connecting the repository:

docker build -t my-api:local .
docker run --rm -p 3000:3000 \
  -e PORT=3000 \
  -e DATABASE_URL=postgresql://user:[email protected]:5432/app \
  my-api:local
curl --fail http://localhost:3000/health

4. Add autodisc.yml

The current CLI uses the version 1 single-service manifest:

version: "1"
name: my-api

source:
  type: repo
  repo_full_name: acme/my-api
  repo_branch: main

runtime:
  stack: dockerfile
  dockerfile: Dockerfile
  start_command: node dist/server.js
  port: 3000

deployment:
  plan_type: starter
  public: true
  auto_restart: true

environment:
  NODE_ENV: production

Use environment only for non-secret defaults. Add secret values in the dashboard. The CLI validates version, name, source.type, deployment.plan_type, runtime.start_command, and the port range before uploading or deploying.

Run:

autodisc login
autodisc deploy --project PROJECT_ID

The current CLI starts the deployment and reports its initial state. It does not yet follow the canonical rollout to a health-gated terminal state. Confirm the result in the project workspace before treating the release as successful.

Multi-service repositories

Keep each independently scalable process separate:

.
├── apps/
│   ├── api/
│   │   └── Dockerfile
│   └── web/
│       └── Dockerfile
├── workers/
│   └── email/
│       └── Dockerfile
└── autodisc.yml

The source-connected preparation path accepts a service map:

services:
  api:
    dockerfile: apps/api/Dockerfile
    workdir: apps/api
    run: node dist/server.js
    port: 3000

  web:
    dockerfile: apps/web/Dockerfile
    workdir: apps/web
    run: node server.js
    port: 3001

  email-worker:
    dockerfile: workers/email/Dockerfile
    workdir: workers/email
    run: node dist/worker.js
    internal: true

internal: true describes a process with no public route. depends_on describes startup ordering; it is not a substitute for connection retries.

The current autodisc deploy CLI schema is single-service. Do not assume it will apply a multi-service manifest atomically. Connect the repository through the project workspace and review the detected Application Plan until CLI multi-service parity is released.

Managed databases

Source-connected projects can declare managed resources and bindings in the repository:

services:
  api:
    dockerfile: apps/api/Dockerfile
    workdir: apps/api
    run: node dist/server.js
    port: 3000

resources:
  customer-data:
    type: postgresql
    class: shared-small

bindings:
  - source: resource.customer-data.connection_url
    target: service.api.environment.DATABASE_URL

Resource keys and service keys are chosen by the repository. Autodisc maps the stable resource type to the selected provider only at apply time. Supported managed types are postgresql, mysql, mariadb, mongo, redis, and libsql.

Resource definitions cannot contain passwords, connection URLs, or arbitrary provider fields. Those values are created by the platform and cross the boundary only through a named output binding.

To use PostgreSQL:

  1. change the application to read DATABASE_URL;
  2. commit migrations with the repository;
  3. declare or approve PostgreSQL in the intended Autodisc environment;
  4. bind its connection_url output to the service's DATABASE_URL;
  5. run migrations once for the release; and
  6. deploy and verify real read/write behavior.

For Redis, use the same pattern with REDIS_URL. Never hardcode an internal resource hostname, provider ID, username, or password in application source.

Release migrations

Do not run destructive migrations in every application replica's startup command. Prefer a release job or an explicitly invoked migration step:

{
  "scripts": {
    "migrate": "prisma migrate deploy",
    "start": "node dist/server.js"
  }
}

Validate migrations against an isolated non-production database first. Back up production before irreversible changes and keep a forward-fix or rollback procedure with the release.

Repository readiness checklist

  • The container builds from a clean checkout.
  • The service listens on 0.0.0.0:$PORT.
  • /health returns success from inside the container.
  • Required dependencies come from named environment variables.
  • .env.example contains names, not real credentials.
  • Logs go to standard output and do not contain secret values.
  • The process exits cleanly after SIGTERM.
  • Database migrations are deterministic and run once per release.
  • Every public service has an intentional port.
  • Workers and schedulers are internal.
  • A non-production deploy has passed build, rollout, health, and functional verification.

What the agent adds

Managed AI can propose the repository changes above and return them as a Change Request. It does not define a different deployment system. Whether the code was written by a person or an agent, Autodisc applies the same repository, artifact, resource, approval, and deployment contracts.

On this page