Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ git clone https://github.com/duplocloud/devkit my-agent && cd my-agent
./run.sh
```

First run asks for an admin **email** — use your **work address**, personal domains (gmail.com, …) are not
accepted — and DuploCloud emails you a **verification link**. Click it and the run continues on its own, then
First run asks for an admin **email** — a work or personal address you can read right now (privacy-relay
and disposable domains are not accepted) — and DuploCloud emails you a **verification link**. Click it and the run continues on its own, then
asks for a **password** and an **LLM provider** and brings the stack up, registering your chosen provider's
model as the **System default LLM**. Sign in at
**<http://localhost:4210>**.
Expand Down
2 changes: 1 addition & 1 deletion docs/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ On an EC2 host the provider prompt first probes whether the instance role can ac
| `--reset-license` | Forget the license as well: the JWT and both ids it can be re-fetched from. Prints the JWT to stderr first, because DuploCloud will not issue a second one for your address. Refused when the run cannot prompt (`-y`, or no tty) and no `--license` replaces it. |
| `--license <jwt>` | Use a license JWT you already have. No licensing call is made. |
| `--non-interactive`, `-y` | Never prompt. A missing required value is an error instead: `Missing <KEY> — pass its flag (non-interactive).` |
| `--email <addr>` | Admin email (your UI login, and the address the license is issued to). Must be a **work** address; personal domains are rejected by the license server. |
| `--email <addr>` | Admin email (your UI login, and the address the license is issued to). Work or personal addresses both work; privacy-relay and disposable domains are rejected by the license server. |
| `--password <pw>` | Admin password. |
| `--model <1\|2\|3\|4\|5\|anthropic\|bedrock\|gateway\|bedrock-instance-role\|subscription>` | LLM provider. `1` is anthropic, `2` is bedrock, `3` is gateway, `4` is bedrock-instance-role, `5` is subscription. Option `4` is only offered at the prompt when the probe proves the role can invoke Bedrock, but `--model bedrock-instance-role` can be passed directly — it then probes and **fails** rather than falling back, since you asked for it explicitly. |
| `--anthropic-key <key>` | Anthropic API key. |
Expand Down
3 changes: 2 additions & 1 deletion docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ run: it requests a **trial license** for your admin email (the company is derive
DuploCloud emails that address a verification link, and the run waits up to 2 minutes for you to click it
before picking the license up and writing it to `Licensing__Token`.

Use a **work address** — the license server rejects personal domains — and note that it issues exactly
Use an address you can receive mail at — work or personal is fine, but the license server rejects
privacy-relay and disposable domains — and note that it issues exactly
**one license per email address**. There is no second trial for the same address, so `run.sh` is built to
never need one: a license it already has is reused, an interrupted verification resumes, and an address the
server already knows is **recovered** (the server emails a confirmation link that releases the same license
Expand Down
9 changes: 5 additions & 4 deletions docs/faq.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,16 @@ Improvements to the *framework* are welcome. Your own extensions belong in your
### Do I need a DuploCloud account?

No account, but three things: the ability to pull `quay.io/duplocloud/*` (run `docker login quay.io` if the
pull is denied), an LLM key for the agent — Anthropic, Azure AI Foundry, or AWS Bedrock — and a **work email
address**, because the stack is licensed. On an EC2 instance whose IAM role can already invoke Bedrock,
pull is denied), an LLM key for the agent — Anthropic, Azure AI Foundry, or AWS Bedrock — and an **email
address you can receive mail at**, because the stack is licensed. On an EC2 instance whose IAM role can already invoke Bedrock,
`run.sh` offers a keyless option and you need no LLM key at all.

### Do I need a license key, and where does it come from?

Yes, and `./run.sh` gets it for you. On first run it requests a trial license for the admin email you enter
and writes the JWT into `.env` as `Licensing__Token`; the studio reads it from there. You have to click a
verification link emailed to that address, so use a work address — personal domains are rejected — and expect
verification link emailed to that address, so use one you can read right now — work or personal is fine, but
privacy-relay and disposable domains are rejected — and expect
one interactive moment on a first install.

The server issues **one license per address** and never a second, so `run.sh` is built never to need one: it
Expand All @@ -72,7 +73,7 @@ Yes. Set `DUPLO_TARGET=remote` with `DUPLO_HOST` and `DUPLO_TOKEN` (an Administr

### What are the prerequisites?

Docker with Compose v2, `python3`, an LLM key, and a work email address you can receive mail at (the license
Docker with Compose v2, `python3`, an LLM key, and an email address you can receive mail at (the license
verification link goes there). That is the whole list — building an extension needs nothing extra on your
machine, because the build runs in a container. See [Prerequisites](getting-started/prerequisites.md).

Expand Down
8 changes: 4 additions & 4 deletions docs/getting-started/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@
**What you'll do:** Clone the dev kit, adopt it as your own repo, bring the platform up with
`./run.sh`, verify your email, and sign in.

**What you need first:** [0. Prerequisites](prerequisites.md) — Docker with Compose v2, Python 3, LLM access, and a
work email address you can read right now.
**What you need first:** [0. Prerequisites](prerequisites.md) — Docker with Compose v2, Python 3, LLM access, and an
email address you can read right now.

---

Expand Down Expand Up @@ -88,7 +88,7 @@ pulls from the official dev-kit URL, whatever you re-point your remote to in the
./run.sh
```

The first prompt is your admin email. Use the work address from
The first prompt is your admin email. Use the address from
[0.4](prerequisites.md#04-an-email-address-you-can-read): it is both your portal login and the address
the verification link is sent to.

Expand All @@ -100,7 +100,7 @@ pulls from the official dev-kit URL, whatever you re-point your remote to in the

## 1.4 Verify your email address

Setup requires a **verified business email address**. `./run.sh` emails you a verification link and
Setup requires a **verified email address** — work or personal. `./run.sh` emails you a verification link and
**the run blocks here until you click it** — then it continues on its own.

1. Watch for this, and go read your inbox:
Expand Down
5 changes: 3 additions & 2 deletions docs/getting-started/prerequisites.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,9 @@ verification link, and the run waits for you to click it before carrying on. So:

- **Use an address you can read right now.** The install blocks until that email arrives and you click
the link.
- **Use a work address.** Personal domains are not accepted — you get
`Re-run with --email <work address> — personal domains are not accepted.` and a chance to retype.
- **Work or personal is fine.** Privacy-relay and disposable domains are not accepted — you get
`Re-run with --email <addr> — most work and personal addresses are accepted; privacy-relay and disposable
domains are not.` and a chance to retype.

The same address becomes your portal login on the next page.

Expand Down
4 changes: 2 additions & 2 deletions docs/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Kubernetes and extension-authoring pages, the full
## 1. Prerequisites

You need Docker with Compose v2, `python3` on your `PATH`, an LLM key (an Anthropic `sk-ant-…` key, or AWS credentials with
access to Bedrock), and a **work email address**.
access to Bedrock), and an **email address you can receive mail at**.

```bash
docker --version && docker compose version
Expand Down Expand Up @@ -41,7 +41,7 @@ docker --version && docker compose version
./run.sh
```

`./run.sh` prompts for `Admin email:` — use the work address. It then **blocks**: DuploCloud emails a
`./run.sh` prompts for `Admin email:` — use an address you can read right now. It then **blocks**: DuploCloud emails a
verification link, and the run waits (up to 2 minutes) for you to click it before continuing on its
own. If the wait times out nothing is lost — click the link, re-run `./run.sh`, and it resumes the same
request without sending a second email.
Expand Down
5 changes: 3 additions & 2 deletions docs/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,8 +159,9 @@ If you already hold the JWT, skip the round trip entirely with `./run.sh --licen

### The license server rejected my email

Personal domains are not accepted. Re-run with a work address — `./run.sh --email you@yourcompany.com`.
A rejected address is not spent, so this is safe to correct.
Work and personal addresses are both accepted; privacy-relay and disposable domains are not. Re-run with a
different address — `./run.sh --email you@example.com`. A rejected address is not spent, so this is safe to
correct.

### The license is for the wrong address

Expand Down
5 changes: 3 additions & 2 deletions hackday/Installing DevKit.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ running platform with no restart. You describe what you want in plain language a
| **Python 3** on your `PATH` | `run.sh` uses it as its `.env` editor and JSON parser |
| **Claude Code** | This is how you build the agent — `/duplo-extension` lives in the repo's `.claude/` |
| **An LLM key** | An Anthropic `sk-ant-…` key, **or** AWS credentials with Bedrock access, **or** an Anthropic-compatible gateway (OpenRouter, Bifrost, LiteLLM) |
| **A work email address** | Personal domains (gmail.com, outlook.com, …) are **rejected** — see the callout in step 2 |
| **An email address you can read** | Work or personal both work; privacy-relay and disposable domains are **rejected** — see the callout in step 2 |
| **Five free ports** | `4210`, `60031`, `8010`, `27018`, `6061`, plus `6333` for Qdrant |

Verify the first two in one line:
Expand Down Expand Up @@ -63,7 +63,8 @@ extension directory — do it now so your Hack Day work has somewhere to live.

> ### ⚠️ The email step will block you — read this first
>
> `run.sh` prompts for `Admin email:`. **Use your work address** — personal domains are not accepted.
> `run.sh` prompts for `Admin email:`. **Use an address you can read right now** — work or personal is fine,
> but privacy-relay and disposable domains are not accepted.
>
> DuploCloud then emails that address a **verification link**, and **the run stops and waits** for you to
> click it, for up to 2 minutes. Click it and the run continues on its own.
Expand Down
10 changes: 5 additions & 5 deletions run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ license_warn_expiry() {
# ISSUED<TAB><message><TAB><recover-path> one trial per email — already used. <recover-path> is set when
# the server says that trial is recoverable; recover it rather than asking
# the user for a JWT they may never have been sent.
# EMAIL<TAB><message> email rejected (personal domain, malformed, …)
# EMAIL<TAB><message> email rejected (privacy-relay or disposable domain, malformed, …)
# ERR<TAB><message> anything else, including transport failure
license_request() { # email api-url
E="$1" U="$2" python3 - <<'PY'
Expand Down Expand Up @@ -790,12 +790,12 @@ if [ -z "$LIC" ]; then
break ;;
EMAIL)
echo " ✖ $MSG" >&2
[ "$NONINTERACTIVE" = 1 ] && { echo " Re-run with --email <work address> — personal domains are not accepted." >&2; exit 1; }
[ "$TRIES" -ge 3 ] && { echo "Giving up after $TRIES attempts — re-run with --email <work address>." >&2; exit 1; }
read -r -p 'Work email: ' EMAIL || { echo "No work email provided — re-run with --email <addr>." >&2; exit 1; }
[ "$NONINTERACTIVE" = 1 ] && { echo " Re-run with --email <addr> — most work and personal addresses are accepted; privacy-relay and disposable domains are not." >&2; exit 1; }
[ "$TRIES" -ge 3 ] && { echo "Giving up after $TRIES attempts — re-run with --email <addr>." >&2; exit 1; }
read -r -p 'Email address: ' EMAIL || { echo "No email provided — re-run with --email <addr>." >&2; exit 1; }
while ! email_valid "$EMAIL"; do
echo "Invalid email address: '${EMAIL:-<empty>}' (expected name@example.com)." >&2
read -r -p 'Work email: ' EMAIL || { echo "No work email provided — re-run with --email <addr>." >&2; exit 1; }
read -r -p 'Email address: ' EMAIL || { echo "No email provided — re-run with --email <addr>." >&2; exit 1; }
done ;;
ISSUED)
# The address already has a trial. When the server can recover it this is not an error the user has
Expand Down
Loading