From the team behind aidrop.it — one workspace to build, host, and keep changing your code.
Every host is a contract: where a process may write, whether anything survives a restart, which port it is given, how many copies run, how much memory it gets, and what outbound traffic is allowed to leave. An agent that picks a stack before reading that contract will choose SQLite on a read-only filesystem, local uploads with no disk, an in-process cache that a restart empties, and SMTP through a network that only lets HTTPS out.
None of that fails the build. It fails after it: at start, on the first request, on the first restart, on the first email. Reading the runtime first changes five decisions, and it costs less than one failed deploy.
A passing build proves almost nothing
A build shows the code compiles and the image assembles. It says nothing about the world the container starts into. The failures that matter arrive later, in a fixed order: writing to a path that is read-only, answering on an address nobody routes to, losing data on the first restart, a client that cannot reach the outside.
Each is cheap to avoid before the code exists and expensive after it, because by then the choice is spread through the application: an ORM configured for a file, an upload handler writing to a directory, a mailer wired to port 587.
Five decisions the runtime makes for you
The runtime settles five design choices before any code is written: where records live, where files go, whether a cache survives, how the application reaches the outside world, and what a single process may assume about itself. An agent that reads the contract first makes each choice once; one that does not makes it twice, the second time after a failure.
- Where records live. No persistent disk means no local database file; the answer is a managed database, reached by a connection string in the environment.
- Where files go. Uploads belong in object storage, not in a directory that a restart clears.
- Whether a cache survives. A cache without a volume empties on restart. Anything that must survive belongs in the database, and a queue belongs where its work is not lost.
- How the app talks to the outside. If outbound traffic leaves through a proxy on web ports only, an HTTP email API works and raw SMTP does not; a database on the public internet may be unreachable by port, not by provider.
- What one process may assume. One replica on one assigned port rules out a second listener; several replicas rule out sessions kept in memory.
Memory and CPU limits are the sixth input: running out of memory kills the process, running out of CPU only makes it slow.
Put the contract where the agent reads it
A contract only helps if it is read at the moment a library is chosen. Either keep it as a file in the repository that the agent's instructions point to, or have the agent read it from the host at the start of a session, along with what is already deployed.
Then ask for the reasoning in the plan, not only in the code: "SQLite is ruled out because the root filesystem is read-only" is a sentence you can check. A plan that names no constraint was written without reading one. Record the build mechanism too, because a Dockerfile nobody names does nothing while the host keeps using its inference path.
A runtime contract worksheet
Fill it in for your host before the first line of code and commit it next to the instructions your agent reads, so every plan can cite it. Then run the checks inside a running container: documentation describes the contract, and the container is the only place that proves it.
RUNTIME CONTRACT — fill in before writing code
Root filesystem at run time: read-write / read-only
Writable paths, size: ________ cleared on restart? y / n
Persistent disk: none / volume at ________
Port: assigned via $PORT / fixed ________
Replicas: one / several
Memory / CPU limit: ________ / ________
Managed services, env vars: database ______ cache ______ queue ______
Survives a restart: database y/n cache y/n queue y/n
Outbound traffic: direct / via proxy allowed ports ______
Build: own Dockerfile / inferred by ________
Health check: path ______ failing it means ______
touch /tmp/probe && echo "tmp is writable"
touch ./probe || echo "app directory is read-only"
env | grep -i -E '^(https?_proxy|port|database_url)='
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com
FAQ
What is a runtime contract? The set of rules a host imposes on a running container: which paths are writable, whether a disk persists, which port it listens on, how many replicas run, its memory and CPU limits, the managed services it can reach, and what outbound traffic may leave. Code that ignores it builds and then fails.
Why does a successful build not mean the app will run? The build only assembles an image. The runtime decides everything after: filesystem permissions, the assigned port, restarts that clear scratch space, and network rules. Most first-deploy failures happen after a green build, at start or on the first request.
Can my app use SQLite in a container? Only with a persistent volume and a single writer. On a host with a read-only root filesystem and no disk, a SQLite file is lost on restart or cannot be written at all; use a managed database instead.
Where does aidrop.it publish its runtime contract? On aidrop.it, service_get returns a runtime_envelope: the CPU and memory limits, no persistent disk and the writable scratch paths with their size, the attached databases, caches and queues with the variable each arrives under and whether it survives a restart, the build, egress and runtime rules, and — for a named runtime kind — a Dockerfile written for those limits.
Get it running from the session you are already in
Connect your coding agent over MCP and ask it to deploy. aidrop builds the repository and runs it on a public address; when a build or the app fails, the log says why, and your agent fixes it and builds again.