Code</>sensei is a thin orchestration layer. It does not host your application, run your database, or proxy your traffic. Everything runs on a server you control. The platform's job is to translate the high-level intent — "deploy this commit of that repository onto that server" — into a sequence of repeatable, inspectable shell operations on the target machine.

The agent model

Most platforms run an in-server agent process that polls a control plane. Code</>sensei does not. Instead, a background worker opens a transient SSH session to your server when there is work to do and disconnects when the work is finished. This has three consequences worth calling out.

First, there is no agent process to update, monitor, or accidentally break. The only software the platform leaves on your server are the release directories your deploys created and the systemd units it wrote to run them. If you cancel your account, those files keep running unchanged.

Second, there is no inbound connection from the platform to your server outside an active deploy window. The platform's worker is the client; your server is the server. SSH key authentication gates the session.

Third, every deploy is fully recorded. The full log of the SSH session, including stdin (commands run) and stdout/stderr (their output), is streamed to your browser in real time and persisted on the deployment row in the platform's database. There is no opaque agent behaviour — what you see in the log is exactly what ran.

Release layout on disk

Each deploy lands in a timestamped directory under a per-project root. The layout follows the Capistrano / Mina convention because it composes well with atomic symlink swaps:

/srv/codesensei/<project-slug>/
  current -> releases/2026-05-21T14-32-08/
  releases/
    2026-05-21T14-32-08/      <-- newest, currently active
    2026-05-20T18-04-55/      <-- previous, kept for rollback
    2026-05-19T09-12-01/      <-- two deploys back
  shared/
    .env
    media/
    logs/

The current symlink is the only path your systemd unit references. Activation is the single ln -snf call that flips that symlink to the new release directory. Until that call, the old release is still serving traffic; after it, the new release is. There is no in-between half-deployed state.

The shared/ directory holds anything that must survive across releases: the .env file, user-uploaded media, log files. Code</>sensei symlinks those into each new release directory at build time, so your application code does not need to be aware of the release layout.

What the worker runs on the server

The deploy script is generated per-deploy from a Jinja2 blueprint that varies by the project's technology field. For a Django project on Debian, the rendered script does roughly the following:

  1. Create the new release directory under /srv/codesensei/<slug>/releases/.
  2. git clone --depth 1 --branch <branch> the project repository into the release directory.
  3. Create or reuse a Python virtual environment at shared/venv/, then pip install -r requirements.txt.
  4. Symlink shared/.env, shared/media/, and shared/logs/ into the release directory.
  5. ./manage.py migrate --noinput.
  6. ./manage.py collectstatic --noinput.
  7. Write the systemd unit at /etc/systemd/system/<slug>.service with the right EnvironmentFile, WorkingDirectory, and the gunicorn or uvicorn invocation appropriate to the project type.
  8. Append the reverse-proxy block that maps the project's public hostname to the application socket and reload the edge proxy.
  9. Flip the current symlink to the new release directory.
  10. systemctl restart <slug>.service.
  11. Optionally prune old release directories beyond the configured retention (default: keep the last five).

Node.js deploys follow the same shape but substitute npm ci / npm run build for the Python steps and use PM2 or a systemd unit running node directly.

Failure handling

If any step in the script exits non-zero, the worker aborts the deploy before flipping the current symlink. The previous release is still serving traffic; from your application's point of view, the failed deploy never happened. The platform's deployment row is marked failed, the captured log is persisted, and the partially-built release directory is left in place so you can SSH in and inspect it.

If the systemd restart fails after the symlink flip (rare, usually a bad environment variable), the deploy is marked failed and the previous release directory still exists; rolling back is a single click and is fast because nothing needs to be rebuilt.

What runs where

ComponentLocationRole
Web app (this site)codesensei.cloudOrchestration, UI, billing, account state
Background workercodesensei.cloudRuns the actual SSH session that performs the deploy
Message brokercodesensei.cloudValkey/Redis on the same VM as the web app; queues deploys
ApplicationYour serverYour code, your data, your processes — we do not have a copy
DatabaseYour server (typically)Whatever your project uses; we never connect to it

The deploy queue

Clicking New deploy creates a deployment row in queued state and enqueues a background job. The job is picked up by the next available worker on the platform, which transitions the row to running, opens the SSH session, executes the deploy script, captures stdout/stderr line by line, and transitions the row to succeeded or failed when the script exits.

The queue is per-server-FIFO: only one deploy runs against any given server at a time. If you queue a second deploy while the first is still running, the new one waits in queued until its predecessor finishes. Queueing across different servers is concurrent — shipping ten unrelated apps at the same time is supported.

If a deploy job exceeds the platform-side timeout (default twenty minutes, configurable per project), the worker terminates the SSH session and marks the deployment row failed with a timeout reason. The half-built release directory on your server is left in place for inspection; the current symlink has not moved.

Why "no in-server agent" matters

The agentless model has a few practical consequences worth calling out beyond the security framing in Security.

Upgrades cost nothing. When we add a new feature to the deploy script — say, automatic database backups before destructive migrations — every server inherits the new behaviour on its next deploy. There is no scheduled agent-version sweep, no failure mode in which half your servers are running the old version and half the new.

Servers can sit idle indefinitely. If you stop deploying for six months, nothing on your server changes. No agent is phoning home in the background to a control plane that may have moved. When you come back, the next deploy fires the platform's current worker against the unchanged server state and the platform handles any distribution upgrades in stride.

Air-gapped subnets work. If your server lives behind a firewall that only allows inbound SSH from a fixed allow-list and denies outbound traffic except for HTTPS to your Git provider, the platform's deploy model still works. The worker connects in, the server pulls code, the deploy completes, the connection closes. There is no persistent connection that needs to stay open through the firewall.