Skip to content
/ minnas Public

Self-hosted distributed app development built for agentic AI

License

Notifications You must be signed in to change notification settings

dinubs/minnas

Repository files navigation

Minnas logo

Minnas

The self-hosted AI project control plane for real workspaces, scheduled runs, and safe deploys.

Minnas app build and chat screen

Minnas is a self-hosted AI project control plane. It gives you a web UI to manage real git workspaces, run Codex-driven assistant/build jobs, automate recurring runs, and deploy with Kamal—all on your own infrastructure.

Go further by chatting with AI with tools provided by the projects you deploy. Schedule runs in one place, to hit all the projects you've deployed. Set up push notifications to be triggered when scheduled runs finish.

Why Not a CLI Script

AI is great at a lot of things, and we've seen it get better and better at running skills, commands, and managing a computer. But these things are slow to interact with if I want to make a quick change to something (say toggle a todo), I shouldn't need to go through a chat interface to do that. Coding Agents are pretty good at one-shotting mini websites to do a small task, that's where Minnas comes in.

Minnas will help you deploy projects to your own self-hosted network, building out actions for you to interact with them via chat agent, but you can also go to them as a hosted service to do what you want as well.

Minnas also deploys as a web-service, think of it as your own personal SaaS assistant. It runs on coding agents like Codex (soon to come are Cursor, and Github Copilot), which can run CLI tools if you ask it too, and Minnas allows it out of the box (runs with --yolo). It can do some dangerous stuff. Though, I trust that it has been trained to avoid doing those things without some major prompting to do it.

Capabilities

  • Project workspaces with persistent logs, artifacts, uploads, and run history.
  • Per-project chats plus a global assistant inbox (threaded conversations, image attachments).
  • On-demand runs (assistant + build) with live log streaming.
  • Scheduled runs (interval, daily, weekly) scoped to a project or global.
  • Action registry from minnas.actions.json so Codex can call your HTTP endpoints; review/edit in the Actions screen.
  • Kamal deploys with saved defaults, templated deploy.yml, and optional simulated deploys.

Architecture

  • Web app: Next.js UI + API routes.
  • Worker: Node process that runs Codex and Kamal.
  • Storage: SQLite + filesystem volumes (/data, /workspaces).

Quick start (Docker)

cp .env.example .env
# set SESSION_SECRET and (optionally) ADMIN_EMAIL

docker compose up --build

Open http://localhost:3000

First-time setup

  1. Visit /setup to create the initial admin account.
  2. If ADMIN_EMAIL is set, the account email must match it.

Storage layout (persistent)

  • DB: /data/app.db
  • Logs: /data/logs/<runId>.log
  • Artifacts: /data/artifacts/<runId>/
  • Uploads: /data/uploads/<messageId>/...
  • Workspaces: /workspaces/<projectId>/repo

Codex auth

  • Go to Admin → Codex Auth and run device auth.
  • Codex auth is stored in CODEX_HOME (default /data/.codex).

SSH keys for deploys

  • Go to Admin → SSH keys to generate a deploy keypair.
  • Add the public key to your target host’s ~/.ssh/authorized_keys.
  • The private key is stored at SSH_PRIVATE_KEY_PATH (default /data/.ssh/id_ed25519).

Chat image support

  • You can attach an image in chat.
  • The image is stored locally (in /data/uploads/...).
  • The Codex prompt is augmented with the local image path.

Actions (tool calls)

Minnas can discover actions defined in a project workspace minnas.actions.json file and publish them as tools for Codex runs.

  • Actions are validated and surfaced in Actions for review/editing.
  • During a run, Minnas can call the action HTTP endpoint against the project's configured deploy target.

Schedules

  • Create interval, daily, or weekly schedules for assistant or build runs.
  • Schedules can target a specific project or the global assistant.

Deploys (Kamal)

Fool‑proof flow:

  1. Create a deploy target (host + SSH user/port).
  2. Save the project deploy config. Saving writes config/deploy.yml into the project workspace.
  3. Click Deploy.

The worker always regenerates config/deploy.yml before running Kamal, so the latest UI config is what gets deployed (and it will commit changes into the project workspace before deploying).

Admin deploy defaults

Set defaults in Admin → Runtime settings so new projects require minimal setup:

  • Default image prefix (e.g. ghcr.io/your-org)
  • Default registry server/username
  • Registry password secret name (value stored in .kamal/secrets)

Custom deploy.yml (with safe template tokens)

If you paste a custom deploy.yml, you can use {{token}} placeholders. Missing values cause a clear error.

Available tokens:

  • {{app.name}}
  • {{app.image}} (includes default image prefix)
  • {{app.image_raw}}
  • {{service.port}}
  • {{registry.server}}
  • {{registry.username}}
  • {{registry.password_secret}}
  • {{ssh.user}}
  • {{ssh.port}}
  • {{ssh.key_path}}
  • {{proxy.hosts}} (comma‑separated)

Example:

image: {{app.image}}

registry:
  server: {{registry.server}}
  username: {{registry.username}}
  password:
    - {{registry.password_secret}}

ssh:
  user: {{ssh.user}}
  port: {{ssh.port}}
  keys:
    - {{ssh.key_path}}

Local test deploy (same machine)

  1. Enable SSH on your machine.
  2. Ensure Docker is running.
  3. Add the host key so Kamal doesn’t prompt during deploy:
ssh-keyscan host.docker.internal >> ~/.ssh/known_hosts
  1. In the Deploy tab, use:
  • Host: host.docker.internal
  • SSH user: your local username
  • Port: 22

Notes:

  • On Linux, host.docker.internal might not resolve; use your machine’s LAN IP.
  • Ensure your SSH user can run Docker on the target host.

HTTPS for private domains (mkcert + Kamal proxy)

If your app is only reachable on a private network (e.g. minnas.sombra), Let’s Encrypt cannot issue a cert. Use a private CA with mkcert and load the PEMs via Kamal secrets.

  1. Create a private cert folder (keep it out of git):
mkdir -p private/certs
echo "private/certs/" >> .gitignore
  1. Generate a private CA and cert:
brew install mkcert
mkcert -install
cd private/certs
mkcert minnas.sombra
  1. Save the root CA so you can install it on devices:
cp "$(mkcert -CAROOT)/rootCA.pem" private/certs/
  1. Store the certs in Kamal secrets:
kamal secrets set MINNAS_CERT_PEM="$(cat private/certs/minnas.sombra.pem)"
kamal secrets set MINNAS_CERT_KEY_PEM="$(cat private/certs/minnas.sombra-key.pem)"
  1. In the Deploy UI, set a Custom deploy.yml (so it is not overwritten):
proxy:
  app_port: 3000
  hosts:
    - minnas.sombra
  ssl:
    certificate_pem: MINNAS_CERT_PEM
    private_key_pem: MINNAS_CERT_KEY_PEM
  forward_headers: true
  1. Install rootCA.pem on each device that needs to trust the cert (macOS Keychain or iOS profile), then redeploy.

Environment variables

Core:

  • ADMIN_EMAIL: email allowed to bootstrap the first user.
  • SESSION_SECRET: HMAC secret for session cookies.
  • DATABASE_URL: default file:/data/app.db.
  • DATA_DIR: override data path (default /data if present).
  • WORKSPACES_DIR: override workspaces path (default /workspaces if present).

Codex:

  • CODEX_API_KEY: API key for Codex CLI.
  • CODEX_HOME: default /data/.codex.
  • CODEX_SANDBOX: override sandbox (e.g. workspace-write).
  • CODEX_STATUS_TTL_SECONDS: cache Codex availability checks (default 60).

Deploy:

  • SSH_PRIVATE_KEY_PATH: default /data/.ssh/id_ed25519.
  • SIMULATE_DEPLOY: set 1 to force deploy simulation.
  • KAMAL_SETUP: set 1 to run kamal setup before deploy.
  • KAMAL_QUIET: set 1 for quieter output.
  • KAMAL_LOG_MODE: default or errors.
  • KAMAL_BUILD_CLEANUP: set 0 to disable build cache cleanup.
  • PROXY_HOSTS: comma-separated default hosts.
  • WORKER_CONCURRENCY: number of jobs the worker can run in parallel (default 1).
  • WORKER_PROJECT_LOCK: set 0 to allow concurrent runs on the same project (default 1).
  • WORKER_PROJECT_LOCK_SCOPE: kind (default) allows different run types in parallel; project blocks all runs per project.

Deploy defaults (admin override env):

  • DEFAULT_IMAGE_PREFIX
  • DEFAULT_REGISTRY_SERVER
  • DEFAULT_REGISTRY_USERNAME
  • DEFAULT_REGISTRY_PASSWORD_SECRET

Development scripts

npm run dev          # Next.js dev server
npm run worker:dev   # Worker loop (ts)
npm run db:generate  # Generate drizzle migrations

Codex CLI

Install the Codex CLI (needed for the worker):

npm i -g @openai/codex

Authenticate (local dev):

codex login

About

Self-hosted distributed app development built for agentic AI

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages