# Projects & environment

Each project gets a permanent slug, which becomes its address: `https://<slug>.harakumo.app`. Creating a project reserves the name; nothing serves until the first deploy succeeds. A project that only holds a database or storage has no website, and that is fine.

## What a project reports

`GET /api/projects/:id` returns `project` (with `live_url`, null until a deploy is live), `serving` (`state`: live, down, deploying, failed or not_deployed, plus the serving deployment), `deployAction` (what Deploy does: rebuild the latest GitHub commit, or redeploy kept files) and `services` (counts of vectors, memory stores, agents, auth pools and media, and the payment account). The project id is on the project's Overview (Connect your app) and Settings.

## Environment variables

- Set them in the dashboard (project → Environment) or with `POST /api/projects/:id/env { key, value }`. A key starts with a letter or an underscore and has only letters, digits and underscores (`API_KEY` and `api_key` both work); anything else is refused with 400, so every key that is accepted reaches your code. Setting an existing key replaces it.
- They are copied into sites, server apps and functions when those deploy. Change one, then redeploy (or press Redeploy) for it to take effect.
- Only the production target is used.
- Values are readable by developers and above, never by viewers or read-only keys. They are not encrypted secrets — do not reuse a value you could not afford a teammate to see.

## Deleting a project

Deleting removes the site, functions, buckets and their files, databases, vector collections, memory stores, media and custom-domain connections. Domains bought in the workspace stay in the workspace and keep renewing.

- Refused with 409 `deletion_blocked` while the project holds unwithdrawn earnings, a pending withdrawal, a checkout link that can still be paid, or a running deploy. `blockers[]` says what to do.
- If something cannot be removed, the answer is 502 `teardown_incomplete`; the project is kept with status teardown_failed, accepts only reads and deletes, and deleting again retries.
- Deleting needs an admin, or a full workspace key. Project keys and read-only keys cannot delete projects.

## Reference

**SDK**

```js
const { project } = await hk.projects.create({ name: 'my-app' });
const { project: p, serving, services } = await hk.projects.get(project.id);   // p.live_url, serving.state
const { projects } = await hk.projects.list();
await hk.projects.delete(project.id);
```

**CLI**

```bash
harakumo projects
harakumo projects create my-app
harakumo projects delete 12
```

**REST**

```http
POST   /api/projects                   { "name": "my-app", "repoUrl"? }
GET    /api/projects                   # each with live_url
GET    /api/projects/:id               # live_url, serving, deployAction, services
PATCH  /api/projects/:id               { "name"?, "repoUrl"?, "repoBranch"?, "mailSenderName"?, "mailFrom"?, "mailReplyTo"? }
DELETE /api/projects/:id               # 409 deletion_blocked · 502 teardown_incomplete
POST   /api/projects/:id/env           { "key": "SHIPPING_API_TOKEN", "value": "…" }   # upsert
GET    /api/projects/:id/env           # developer+
PATCH  /api/projects/:id/env/:envId · DELETE /api/projects/:id/env/:envId
```
