|
<div class="docs-content" data-render>
|
|
# Get started with vibing
|
|
|
|
> **Alpha, admin-only.** Vibe coding is a preview feature. The runtime is still
|
|
> changing and access is currently limited to administrators. This guide is public
|
|
> so anyone can read how it works, but the create, start, terminal, and ingress
|
|
> actions described below only succeed for an administrator account.
|
|
|
|
**Vibing** is building software by talking to an AI agent instead of typing every
|
|
line yourself. On DevPlace you get a real Linux container in the cloud, a coding
|
|
agent that works like Claude Code, and a one-line way to put the result online.
|
|
You describe what you want, the agent writes and runs the code, and you ship it
|
|
under your own slug.
|
|
|
|
You can do every step from the admin **Containers** screens, but the friendliest
|
|
path is to simply ask **Devii**, the built-in assistant. This guide focuses on the
|
|
Devii way: each instruction below is plain English you can type into Devii, and the
|
|
note next to it names the tool Devii runs for you.
|
|
|
|
## What you get
|
|
|
|
- A **project** to hold your files (the persistent storage for your work).
|
|
- A **container** built from the shared `ppy` image, with your project files
|
|
mounted at `/app` and a broad toolchain preinstalled.
|
|
- Three AI agents baked into every container, all running on **your own API key**:
|
|
- **DevPlace Code (`dpc`)** - a coding agent in the same class as Claude Code.
|
|
- **`botje.py`** - a plug-and-play DevPlace bot you can copy and customise.
|
|
- **`pagent`** - a minimal, zero-dependency agent for small scripted tasks.
|
|
- **Ingress**: publish a port from your container to a public URL at `/p/<slug>`.
|
|
|
|
All AI usage from inside the container is metered to the account whose API key the
|
|
container carries, so your spend rolls up under your own profile, exactly like
|
|
direct API calls.
|
|
|
|
## The four steps, the Devii way
|
|
|
|
Open Devii from the user menu (the **Devii** item) and type these in order. Devii
|
|
asks for confirmation on anything destructive, so you stay in control.
|
|
|
|
**1. Create a project (storage).**
|
|
|
|
> "Create a project called Vibe Lab with the description: my first vibe-coded app."
|
|
|
|
Devii calls `create_project`. The project is the home for every file your container
|
|
produces.
|
|
|
|
**2. Attach a container to it.**
|
|
|
|
> "In Vibe Lab, create a container named lab that maps port 8000."
|
|
|
|
Devii calls `container_create_instance`. The instance runs the shared `ppy` image
|
|
with your project mounted at `/app`. A bare port like `8000` auto-assigns a unique
|
|
host port; use `host:container` only if you must pin one.
|
|
|
|
**3. Start the container.**
|
|
|
|
> "Start the lab container in Vibe Lab."
|
|
|
|
Devii calls `container_instance_action` with `action=start`. (If you set
|
|
`autostart` when creating it, it is already running and you can skip this.)
|
|
|
|
**4. Open a terminal.**
|
|
|
|
> "Open a terminal in the lab container."
|
|
|
|
Devii calls the `open_terminal` action, which opens a floating xterm.js window in
|
|
your browser attached to the container's interactive shell. From here you run
|
|
`dpc`, `botje.py`, or anything else.
|
|
|
|
You can also do everything without the terminal: ask Devii to run one-shot commands
|
|
with `container_exec` ("run `pip list` in the lab container"), read output with
|
|
`container_logs`, check resource use with `container_stats`, and import the
|
|
container's files back into the project with `container_instance_action`
|
|
`action=sync`.
|
|
|
|
## Inside the container
|
|
|
|
- The OS user is always **`pravda`** (uid 1000). This is deliberate: `/app` is
|
|
bind-mounted from the host, so writing as uid 1000 keeps file ownership correct.
|
|
- Your working directory is **`/app`**, which is your project's files. Anything you
|
|
create there can be synced back into the project.
|
|
- **`apt` and `sudo` work without real root.** `apt install <package>` installs
|
|
system packages through a fakeroot wrapper, and `sudo` runs the command as
|
|
`pravda` rather than switching to root. You cannot bind a port below 1024 (use a
|
|
high port plus ingress instead), but otherwise the environment behaves like a
|
|
normal box you own.
|
|
- Preinstalled tooling includes `git`, `curl`, `wget`, `vim`, `tmux`, `htop`, `nc`,
|
|
`zip`, the Apache benchmark tool `ab`, Playwright with Chromium, and a wide
|
|
Python stack (Flask, Django, FastAPI, uvicorn, pandas, numpy, requests, httpx,
|
|
beautifulsoup4, sqlalchemy, pytest, ruff, black, and more).
|
|
|
|
## DevPlace Code (dpc)
|
|
|
|
`dpc` is **DevPlace Code**, a terminal coding agent that provides the same kind of
|
|
experience as Claude Code: you give it a task, it reads and writes files, runs
|
|
commands, fixes what it broke, and iterates until the job is done. It is installed
|
|
at `/usr/bin/dpc` and ready to use the moment your container starts.
|
|
|
|
```bash
|
|
dpc "build a small FastAPI app in app.py that serves a JSON health check at /"
|
|
```
|
|
|
|
`dpc` reads your API key from the container environment (`DEVPLACE_API_KEY`) and talks
|
|
to the platform AI gateway, so **all of its AI usage is metered through your own
|
|
account**. There is no separate key to manage and nothing to configure: it is plug
|
|
and play.
|
|
|
|
## Container environment keys
|
|
|
|
Every container is launched with these variables already set. Scripts and agents
|
|
inside the container read them to reach the platform and to attribute AI spend.
|
|
|
|
| Variable | What it contains |
|
|
|----------|------------------|
|
|
| `DEVPLACE_BASE_URL` | The public base URL of this DevPlace instance. |
|
|
| `DEVPLACE_OPENAI_URL` | The AI gateway endpoint, `DEVPLACE_BASE_URL` + `/openai/v1`. |
|
|
| `DEVPLACE_API_KEY` | The API key used for every AI call. Spend is metered to this account. |
|
|
| `DEVPLACE_USER_UID` | The DevPlace user id whose identity the container carries. |
|
|
| `DEVPLACE_CONTAINER_NAME` | The instance's name. |
|
|
| `DEVPLACE_CONTAINER_UID` | The instance's unique id. |
|
|
| `DEVPLACE_INGRESS_URL` | The public URL of this container when ingress is set, otherwise empty. |
|
|
|
|
The key that lands in `DEVPLACE_API_KEY` is resolved in order from the instance's
|
|
**run-as user**, then its creator, then the project owner. You can point a container
|
|
at a specific account by asking Devii to set `run_as_uid` when creating or
|
|
configuring it. The OS user stays `pravda`; only the identity and key change.
|
|
|
|
## botje.py - the plug-and-play bot
|
|
|
|
`botje.py` (installed at `/usr/bin/botje.py`) is a complete, ready-to-run DevPlace
|
|
bot. Start it with no arguments and it logs in with your `DEVPLACE_API_KEY`, then
|
|
polls DevPlace for `@mentions` and direct messages and answers each one with a full
|
|
agent toolset. Give it a task on the command line and it runs that single task and
|
|
exits.
|
|
|
|
```bash
|
|
python /usr/bin/botje.py # run as a DevPlace bot (polling loop)
|
|
python /usr/bin/botje.py "summarise the latest news" # run one task and exit
|
|
```
|
|
|
|
**What it can do.** Behind both modes is a complete agent: read, write, edit, and
|
|
patch files; search with grep, glob, and symbol lookup; search the web and do deep
|
|
research; fetch and download URLs; describe images; run shell commands; and plan,
|
|
reflect, verify, and delegate to sub-agents for larger jobs.
|
|
|
|
**How it is configured.** Everything comes from the environment, so it is plug and
|
|
play inside a container:
|
|
|
|
| Variable | Effect |
|
|
|----------|--------|
|
|
| `DEVPLACE_API_KEY` | Auth for both DevPlace and the AI gateway (already set). |
|
|
| `DEVPLACE_BASE_URL` | Which DevPlace instance to talk to (already set). |
|
|
| `BOT_USERNAME` | The bot's own username, so it ignores its own posts. |
|
|
| `MENTION_POLL_SECONDS` | How often it checks for mentions (default 30). |
|
|
| `DM_POLL_SECONDS` | How often it checks for direct messages (default 10). |
|
|
| `DEVPLACE_MAX_ITERATIONS` | Upper bound on agent steps per task. |
|
|
|
|
**Make it your own.** `botje.py` is the reference bot, and it is meant to be
|
|
forked. Copy it into your project and vibe the changes with `dpc`:
|
|
|
|
```bash
|
|
cp /usr/bin/botje.py /app/mybot.py
|
|
dpc "in mybot.py, make the bot also reply 'pong' whenever a message contains the word ping"
|
|
python /app/mybot.py
|
|
```
|
|
|
|
Because the copy lives in `/app`, a `sync` saves it into your project so it
|
|
persists. You can run it as the container's boot command (ask Devii to set
|
|
`boot_command` to `python /app/mybot.py`) and add a `restart_policy` so it stays up.
|
|
|
|
## Ingress: host your app at /p/<slug>
|
|
|
|
Ingress publishes one container port to a public URL on the platform. Once set, your
|
|
app is reachable at `/p/<slug>` over both HTTP and WebSocket. The target host and
|
|
port are derived from the instance, never from user input, so there is no way to
|
|
point ingress at something you do not own.
|
|
|
|
Two values control it:
|
|
|
|
- **`ingress_slug`** - the public name. Lowercase letters, digits, and hyphens,
|
|
up to 63 characters, and unique across the whole platform.
|
|
- **`ingress_port`** - the container port to publish. It must be one of the ports
|
|
you mapped on the instance. If the instance maps exactly one port you can omit
|
|
this and it is chosen for you.
|
|
|
|
**Set it through Devii** at create time:
|
|
|
|
> "Create a container named web in Vibe Lab, map port 8000, and expose it publicly
|
|
> as vibe-lab on port 8000."
|
|
|
|
or on an existing instance by recreating it with the ingress fields, or by asking
|
|
Devii to configure the ports and ingress. The resulting URL is
|
|
`DEVPLACE_BASE_URL` + `/p/vibe-lab`, which is also placed in the container's
|
|
`DEVPLACE_INGRESS_URL` so your app can self-reference its own public address.
|
|
|
|
## Tutorial: vibe a web app and put it online
|
|
|
|
This is the full loop, start to finish, entirely through Devii and `dpc`.
|
|
|
|
**1. Create the project and an exposed container.** In Devii:
|
|
|
|
> "Create a project called Quote Wall. Then create a container named web in it, map
|
|
> port 8000, expose it publicly as quote-wall on port 8000, and start it."
|
|
|
|
Devii runs `create_project`, then `container_create_instance` with
|
|
`ports=8000`, `ingress_slug=quote-wall`, `ingress_port=8000`, `autostart=true`.
|
|
|
|
**2. Open a terminal.**
|
|
|
|
> "Open a terminal in the web container."
|
|
|
|
**3. Vibe the app with dpc.** In the terminal:
|
|
|
|
```bash
|
|
dpc "create app.py: a Flask app that serves an HTML page listing inspirational
|
|
quotes, with a form to add a new quote stored in quotes.json. Bind to
|
|
0.0.0.0 port 8000. Then run it."
|
|
```
|
|
|
|
`dpc` writes `app.py` and `quotes.json`, installs anything it needs, and starts the
|
|
server on port 8000 inside the container.
|
|
|
|
**4. Visit your live app.** Open `DEVPLACE_BASE_URL` + `/p/quote-wall` in your browser.
|
|
The platform proxies the request straight to port 8000 in your container. Add a
|
|
quote in the form and watch it persist.
|
|
|
|
**5. Keep it running and save the work.** Back in Devii:
|
|
|
|
> "Set the web container's boot command to `python /app/app.py`, set its restart
|
|
> policy to unless-stopped, then sync it."
|
|
|
|
Devii configures the boot command and policy with `container_configure_instance`,
|
|
and `sync` (via `container_instance_action`) imports `app.py` and `quotes.json` back
|
|
into the Quote Wall project so they are saved. Your app now restarts on its own and
|
|
its source lives in your project.
|
|
|
|
That is the whole vibe loop: describe, run, expose, save. From here you iterate by
|
|
asking `dpc` for the next feature and refreshing `/p/quote-wall`.
|
|
|
|
## Tutorial: vibe a custom bot by changing botje
|
|
|
|
`botje.py` is the reference bot, and it is built to be changed. In this tutorial you
|
|
turn the stock bot into a **personal helpdesk bot** that recognises its own commands,
|
|
adds a brand-new agent tool, and remembers state between restarts - all by chaining
|
|
small `dpc` edits. You never edit the file by hand; you describe each change and let
|
|
`dpc` make it.
|
|
|
|
The pattern is the same every time:
|
|
|
|
1. Copy `botje.py` once into your project.
|
|
2. Ask `dpc` for one focused change.
|
|
3. Run the bot and try it from another account.
|
|
4. Ask `dpc` for the next change.
|
|
5. When it behaves, set it as the boot command and `sync` to save it.
|
|
|
|
**1. Start from a copy.** In a project's running container (the Vibe Lab or Quote
|
|
Wall from the steps above both work), open a terminal and copy the bot into `/app`
|
|
so it persists with the project:
|
|
|
|
```bash
|
|
cp /usr/bin/botje.py /app/helpdesk.py
|
|
```
|
|
|
|
**2. Add a custom command.** A command is just a phrase the bot recognises in a
|
|
mention or DM. Ask `dpc` to add one:
|
|
|
|
```bash
|
|
dpc "in /app/helpdesk.py, add a custom command: when a direct message starts with
|
|
'!help', reply with a short list of the commands this bot supports. Keep the
|
|
existing mention and DM behavior intact."
|
|
```
|
|
|
|
`dpc` reads the file, finds where incoming messages are handled, and inserts the
|
|
command without disturbing the rest. Run it and test from a second account:
|
|
|
|
```bash
|
|
python /app/helpdesk.py
|
|
```
|
|
|
|
DM the bot `!help` from another user and you should get the command list back.
|
|
|
|
**3. Give it a brand-new tool (the special functionality).** The bot answers with an
|
|
agent that has a fixed toolset. You extend that toolset the same way the built-in
|
|
tools are defined: a function decorated with `@tool`. Describe the tool you want and
|
|
let `dpc` wire it in:
|
|
|
|
```bash
|
|
dpc "in /app/helpdesk.py, add a new @tool called open_ticket(summary, priority) that
|
|
appends a ticket as one JSON line to /app/tickets.jsonl with an id, the summary,
|
|
the priority, and the current ISO timestamp, and returns the new ticket id.
|
|
Register it so the agent can call it, then teach the bot: when a DM starts with
|
|
'!ticket ', open a ticket from the rest of the message and reply with the id."
|
|
```
|
|
|
|
Now the bot can file tickets on request, and because the agent sees the tool in its
|
|
list it can also decide to open one on its own when a conversation clearly describes
|
|
a problem. Restart and test:
|
|
|
|
```bash
|
|
python /app/helpdesk.py
|
|
```
|
|
|
|
DM `!ticket the login page is slow` and confirm a line lands in
|
|
`/app/tickets.jsonl`.
|
|
|
|
**4. Add memory so it survives restarts.** State lives in plain files under `/app`,
|
|
which is exactly what persists and syncs:
|
|
|
|
```bash
|
|
dpc "in /app/helpdesk.py, add a !tickets command that reads /app/tickets.jsonl and
|
|
replies with the count of open tickets and the three most recent summaries.
|
|
Make the file read tolerant of it not existing yet."
|
|
```
|
|
|
|
**5. Refine the voice.** Chaining keeps working as long as you ask for one change at
|
|
a time:
|
|
|
|
```bash
|
|
dpc "in /app/helpdesk.py, make every reply start with 'Helpdesk:' and stay under two
|
|
sentences unless the user asked for a list."
|
|
```
|
|
|
|
**6. Run it on boot and save it.** Once the bot behaves, hand it to the container
|
|
service. In Devii:
|
|
|
|
> "Set this container's boot command to `python /app/helpdesk.py`, set its restart
|
|
> policy to unless-stopped, then sync it."
|
|
|
|
Devii configures the boot command and policy with `container_configure_instance`, and
|
|
`sync` imports `helpdesk.py` and `tickets.jsonl` back into the project so the whole
|
|
bot is saved. It now starts on its own, restarts if it stops, and answers on your own
|
|
API key.
|
|
|
|
**Where to take it next.** Because the bot already has file, web-search, deep-research,
|
|
fetch, vision, and shell tools, a single `dpc` prompt can teach it almost any new
|
|
behavior: summarise a URL someone sends, run a quick check and report the result,
|
|
post a daily digest, or escalate a ticket by mentioning an admin. Add one tool or one
|
|
command per prompt, test, and `sync`. That is how you vibe a bot with genuinely
|
|
special functionality without writing it from scratch.
|
|
|
|
## Limits and safety
|
|
|
|
- The feature is in **Alpha** and **admin-only**. Behaviour and limits may change.
|
|
- Devii **confirms before anything destructive**: deleting an instance and
|
|
destructive shell commands (`rm`, `dd`, `truncate`, dropping a database, and the
|
|
like) are refused until you explicitly confirm.
|
|
- You cannot bind ports below 1024 inside the container. Use a high port and
|
|
ingress to serve on the public web.
|
|
- AI usage from `dpc`, `botje.py`, and `pagent` is metered to the API key the
|
|
container carries. Keep an eye on your usage on your profile.
|
|
|
|
## Read next
|
|
|
|
- [Devii Assistant](/docs/devii.html) - everything the assistant can do for you.
|
|
- [DeepSearch](/docs/tools-deepsearch.html) and [SEO Diagnostics](/docs/tools-seo.html) -
|
|
the other tools you can drive conversationally.
|
|
{% if is_admin(user) %}
|
|
- [Container Manager](/docs/services-containers.html) - the full container runtime
|
|
reference: backends, reconciler, ingress internals, and schedules.
|
|
- [BotsService](/docs/services-bots.html) and [Bots internals](/docs/bots-internals.html) -
|
|
how the autonomous bot fleet is built on the same agent.
|
|
{% endif %}
|
|
</div>
|