Docs menu

Getting started

Let your agent set up Lampwick

A coding agent creates a Lampwick workspace without an account, connects your app and hands you a claim link. You claim it and decide what the agent may keep.

Updated View as Markdown

On this page

Ask Claude Code, Cursor or Codex to add Lampwick to your app. The agent creates a trial workspace with POST /api/v1/workspaces, connects your app and checks that the first event arrived. Then it gives you a claim link: you claim the workspace in your own account and decide whether the agent stays connected.

This page is for you and for the agent. An agent should read it in full before it makes the first request.

The prompt

Paste this into your agent, in the repository of the app you want to monitor:

Set up Lampwick monitoring for this app. Read https://lampwick.dev/docs/agents.md and follow it. Keep the tokens out of the chat, use a dev or staging environment, and give me the claim link when the first event has arrived.

Claude Code

Start claude in the repository and paste the prompt. Claude Code asks before it runs curl and python3; approve those. It sets up everything over the REST API, so it doesn't need the MCP server in this session.

Cursor

Open the repository, switch the chat to Agent and paste the prompt. Cursor runs the commands in its terminal and asks you to approve each one.

Codex

Start codex in the repository and paste the prompt. The requests need network access: approve them when Codex asks.

What happens

  1. The agent creates a workspace. It solves a short proof-of-work and calls POST /api/v1/workspaces. It gets a workspace token (lws_…), the first project with its ingest token, and a claim link (https://app.lampwick.dev/claim/lwc_…).
  2. It connects your app. It puts both tokens in .env, installs the Laravel package or sends data over HTTP ingest, and can add up to 3 uptime monitors.
  3. It checks its work. getSetupStatus says whether the first event arrived (ready_to_hand_off) and what still blocks it.
  4. It hands you the link. It sends you the text of handoff_message with the claim link.
  5. You claim it. You log in or create an account, click Claim workspace, and choose whether the agent keeps access. If it does, you give it a short code.

Nobody gets an email in this flow. No alerts go out until you claim the workspace.

Create the workspace (for agents)

Base URL: https://app.lampwick.dev/api/v1. Every response is JSON. Every error has code and message. The errors of the workspace endpoints, of a refused operation (allowlist or read-only token) and of createMonitor also have agent_hint, which says what to do next.

The commands need curl and python3. Each block below is one command that works on its own, in a fresh shell, from the root of the app's repository. Values carry over through two files: .env (the tokens) and .lampwick-workspace.json (the full response). Neither may end up in git or in the chat.

1. Keep the response out of git

Terminal
touch .gitignore; [ -s .gitignore ] && [ -n "$(tail -c1 .gitignore)" ] && echo >> .gitignore; grep -qxF .lampwick-workspace.json .gitignore || echo .lampwick-workspace.json >> .gitignore; grep -qxF .env .gitignore || echo "Add .env to .gitignore before you go on."

2. Solve the challenge and create the workspace

GET /workspaces/challenge returns a challenge and bits. The command finds a decimal nonce such that sha256(challenge + nonce) (the two strings joined, as UTF-8) starts with bits zero bits, and sends it with POST /workspaces right away: a challenge works for 10 minutes and only once. At 22 bits that is about 4 million hashes, a few seconds in Python. Don't loop over openssl in a shell; one process per hash takes hours.

POST /workspaces takes no authentication and is not an MCP tool. Replace TEAM_NAME, PROJECT_NAME and AGENT_NAME:

Terminal
R=$(curl -s https://app.lampwick.dev/api/v1/workspaces/challenge) && \
CHALLENGE=$(echo "$R" | python3 -c 'import json,sys;print(json.load(sys.stdin)["challenge"])') && \
BITS=$(echo "$R" | python3 -c 'import json,sys;print(json.load(sys.stdin)["bits"])') && \
NONCE=$(python3 -c 'import hashlib,itertools,sys;c,b=sys.argv[1],int(sys.argv[2]);print(next(n for n in itertools.count() if int.from_bytes(hashlib.sha256((c+str(n)).encode()).digest(),"big")>>(256-b)==0))' "$CHALLENGE" "$BITS") && \
curl -s -X POST https://app.lampwick.dev/api/v1/workspaces -H 'Content-Type: application/json' \
  -d "{\"team_name\":\"TEAM_NAME\",\"project_name\":\"PROJECT_NAME\",\"agent\":\"AGENT_NAME\",\"pow\":{\"challenge\":\"$CHALLENGE\",\"nonce\":\"$NONCE\"}}" \
  > .lampwick-workspace.json && \
python3 -c 'import json,sys;d=json.load(open(".lampwick-workspace.json"));print(d.get("error") or {"created": d["workspace"]["name"], "project_id": d["project"]["id"], "expires_at": d["workspace"]["expires_at"]})'

The last line prints the error, or the workspace's name, project id and deadline, without the secrets. To find the nonce with Node, use this in place of the NONCE=$(python3 …) part (the other steps still use python3 to read JSON):

Terminal
NONCE=$(node -e 'const[c,b]=process.argv.slice(1),h=require("crypto");for(let n=0;;n++){const d=h.createHash("sha256").update(c+n).digest();let z=0;for(const x of d){if(x){z+=Math.clz32(x)-24;break}z+=8}if(z>=+b){console.log(n);break}}' "$CHALLENGE" "$BITS")
FieldRequiredWhat it is
team_nameyesThe workspace's name, usually the company or the app (Acme).
project_nameyesThe first project (acme-web).
agentyesYour own name, as the person sees it on the claim page (Claude Code). It is shown as "name not verified".
emailnoYour human's email address. Only an account with exactly that confirmed address can claim the workspace. See bind the claim to an email.
powyes{"challenge": "…", "nonce": "…"}. The nonce may be a string or a number.

Names are 1 to 40 characters: letters, digits, spaces and . - _.

The answer is 201 Created. Trimmed, with the secrets replaced by …:

JSON
{
  "claim_bound_to_email": false,
  "claim_url": "https://app.lampwick.dev/claim/lwc_…",
  "handoff_message": "Lampwick is set up for Acme. Open this link to put it in your name: https://app.lampwick.dev/claim/lwc_… — claim it before Thu 12 Nov, 17:40 UTC, or it stops and is deleted. Anyone with this link can claim it, so keep it to yourself. Lampwick won't email you about it, and no alerts go out until you claim it. After claiming you'll see a short code: give it to me if you want me to stay connected.",
  "limits": { "bytes": 50000000, "events": 10000, "host_checks": 3, "min_interval_secs": 300, "monitors": 3, "projects": 2 },
  "mcp_url": "https://app.lampwick.dev/mcp",
  "not_available_until_claimed": ["alert_channels", "status_pages", "crawler", "invites", "browser_ingest", "billing"],
  "project": { "id": 3, "name": "acme-web", "ingest_token": { "secret": true, "value": "…" } },
  "token": { "header": "Authorization: Bearer lws_…", "secret": true, "value": "lws_…" },
  "workspace": { "id": 2, "name": "Acme", "expires_at": "2026-11-12T17:40:24.907295Z", "deleted_at": "2026-11-13T17:40:24.907295Z" }
}

The response also has api_base, terms_url and next_steps, the same steps as on this page.

FieldWhat to do with it
token.valueThe workspace token (lws_…). Send it as Authorization: Bearer to the API and MCP. Stored as LAMPWICK_WORKSPACE_TOKEN.
project.ingest_token.valueThe project's ingest token. Your app sends data with it. Stored as LAMPWICK_TOKEN.
claim_urlThe link for your human. Single use.
handoff_messageThe text to give your human, with the link and the deadline in it.
workspace.expires_atIngest stops here, 72 hours after creation.
workspace.deleted_atThe workspace is deleted here, 24 hours later. Claiming works until then.
limits, not_available_until_claimedWhat the workspace can do before the claim.

3. Store the tokens in .env

Fields with "secret": true go in .env, never in the chat. The first part adds a final newline if .env lacks one, so the new lines don't join the last one:

Terminal
touch .env; [ -s .env ] && [ -n "$(tail -c1 .env)" ] && echo >> .env; python3 -c 'import json;d=json.load(open(".lampwick-workspace.json"));print("LAMPWICK_WORKSPACE_TOKEN="+d["token"]["value"]);print("LAMPWICK_TOKEN="+d["project"]["ingest_token"]["value"])' >> .env

The commands below read the tokens back from .env. Delete .lampwick-workspace.json once you have handed off the claim link.

4. Connect the app

Until a person claims the workspace there is no data processing agreement. Use a dev or staging environment and don't send production data yet.

For Laravel:

Terminal
composer require lampwick/laravel && php artisan lampwick:test

lampwick:test reads LAMPWICK_TOKEN from .env and sends a test record, which counts as the first event. It also checks the ingest daemon, and exits 1 while the daemon isn't running; its test record still counts. Then start the ingest daemon (php artisan lampwick:agent) in this environment and load a page, so real requests arrive. The daemon keeps running: start it in the background or a second terminal, and in production under a process manager (Laravel docs).

For any other app, send a record over HTTP:

Terminal
curl -s -X POST https://app.lampwick.dev/ingest \
  -H "Authorization: Bearer $(grep '^LAMPWICK_TOKEN=' .env | cut -d= -f2-)" \
  -H "Content-Type: application/json" \
  -d '[{"t":"log","level":"info","message":"Lampwick test event"}]'

The answer is {"accepted":1} with status 202. Send the first event within 6 hours: a workspace without any event by then is deleted as idle.

5. Add uptime monitors (optional)

Terminal
curl -s -X POST "https://app.lampwick.dev/api/v1/projects/$(python3 -c 'import json;print(json.load(open(".lampwick-workspace.json"))["project"]["id"])')/monitors" \
  -H "Authorization: Bearer $(grep '^LAMPWICK_WORKSPACE_TOKEN=' .env | cut -d= -f2-)" -H 'Content-Type: application/json' \
  -d '{"url":"https://staging.example.com","interval_secs":300}'

Replace the URL with your app's. Before the claim: public URLs only, every 5 minutes or slower (interval_secs 300 or more), at most 3 monitors, and at most 10 new monitors and URL changes a day. SSL, domain and DNS checks are on for each monitor.

6. Check the setup

Terminal
curl -s https://app.lampwick.dev/api/v1/setup-status -H "Authorization: Bearer $(grep '^LAMPWICK_WORKSPACE_TOKEN=' .env | cut -d= -f2-)"

This is getSetupStatus on MCP. Before the first event:

JSON
{
  "ready_to_hand_off": false,
  "blocking": ["no events yet from acme-web"],
  "next_action": "Fix this first: no events yet from acme-web. Send a test event with the ingest token (or trigger an error in the app), then call getSetupStatus again.",
  "hours_left": 72.0
}

After it:

JSON
{
  "ready_to_hand_off": true,
  "blocking": [],
  "next_action": "Give your human the claim link with the text of handoff_message.",
  "projects": [{ "id": 3, "name": "acme-web", "first_event_at": "2026-11-09T17:40:47.648610Z", "last_deploy_at": null }]
}

The full answer also has claimed, claimed_by, expires_at, deleted_at, monitors with their status, usage, limits, agent_access and access_expires_at. A monitor that is down also blocks the hand-off. ready_to_hand_off only says that one event arrived: for a Laravel app, check that the ingest daemon runs before you hand off.

7. Hand off

When ready_to_hand_off is true, give your human the text of handoff_message:

Terminal
python3 -c 'import json;print(json.load(open(".lampwick-workspace.json"))["handoff_message"])'

Lost the link, or it leaked? POST /workspace/claim-link makes a new one, with a new handoff_message; the old link stops working. It never extends the deadline. This command saves the new link in .lampwick-workspace.json and prints the new handoff_message:

Terminal
curl -s -X POST https://app.lampwick.dev/api/v1/workspace/claim-link -H "Authorization: Bearer $(grep '^LAMPWICK_WORKSPACE_TOKEN=' .env | cut -d= -f2-)" | python3 -c '
import json, sys
new, f = json.load(sys.stdin), ".lampwick-workspace.json"
if "claim_url" not in new: sys.exit(json.dumps(new))
d = json.load(open(f)); d["claim_url"], d["handoff_message"] = new["claim_url"], new["handoff_message"]
json.dump(d, open(f, "w")); print(d["handoff_message"])'

Keep calling getSetupStatus. With under 24 hours left, its next_action says to remind your human.

8. Confirm the code

After the claim, getSetupStatus shows "claimed": true, "agent_access": "pending_code", and this next_action:

Claimed. Ask your human for the code on the page they see after claiming (like K7P-92Q) and call confirmWorkspaceAccess within 15 minutes, or you lose access and the ingest tokens are replaced.

Ask for the code, then send it (replace K7P-92Q):

Terminal
curl -s -X POST https://app.lampwick.dev/api/v1/workspace/confirm \
  -H "Authorization: Bearer $(grep '^LAMPWICK_WORKSPACE_TOKEN=' .env | cut -d= -f2-)" -H 'Content-Type: application/json' \
  -d '{"code":"K7P-92Q"}'

This is confirmWorkspaceAccess on MCP. Case and the dash don't matter. The answer:

JSON
{
  "agent_access": "read",
  "access_expires_at": "2026-12-09T17:41:05.984592Z",
  "next_action": "You keep read-only access until Wed 9 Dec, 17:41 UTC; after that, ask your human to connect you with OAuth."
}

Your token now has the access your human chose, read or write, until 30 days after the claim. After that, connect with OAuth.

Use MCP (optional)

The same token works on the MCP server, which lists only the tools the token may use. In Claude Code:

Terminal
claude mcp add --transport http lampwick https://app.lampwick.dev/mcp --header "Authorization: Bearer $(grep '^LAMPWICK_WORKSPACE_TOKEN=' .env | cut -d= -f2-)"

This stores the token in Claude Code's own settings. A server you add mid-session is usually loaded in the next session; use the REST calls above to finish the setup. Other clients: the MCP docs, with LAMPWICK_WORKSPACE_TOKEN in place of LAMPWICK_TOKEN.

Claim the workspace (for people)

Open the link your agent gave you. The page shows who set it up ("Claude Code · name not verified"), when, what it holds (projects, monitor URLs and events) and when it is deleted.

Only claim it if you asked an agent to set up Lampwick yourself. A claim link from someone else is a way to get you to connect your app to their workspace.

  1. Click Log in or Create account. You come back to the page afterwards. Claiming needs a confirmed email address.
  2. Check Claiming as and click Claim workspace. The workspace becomes your team, on the Free plan. Free has 1 project; a workspace can have 2. Both stay and keep their data, but the team can't add another project until you upgrade.
  3. On the next page, choose what the agent may do: Read-only (recommended) or Read & write.
  4. Click Show code for the agent and give the code (like K7P-92Q) to your agent. It works within 15 minutes of the claim.

Without the code, the agent loses all access and your ingest tokens are replaced; the page shows the new ones, to put in .env. The real pages, with example data: the claim page and the code.

If you already have a Free team, each account gets one active Free team:

  • The projects fit in it: the page offers Add to your team (recommended). The projects move there with new ingest tokens and the agent is disconnected. It never gets access to a team you already had. Connect it again with OAuth if you want. New team is the other choice, but that team receives no data until one of the two is upgraded.
  • They don't fit: you can only claim it as a new team, and the page warns that it stays inactive (receives no data) until one of your teams is upgraded.

Lampwick sends you a "You claimed Acme" email with a Manage agent access link, and a reminder 3 days before the agent's access ends.

What the agent can do

Before the claimAfter the claim, with the code
ProjectsCreate and read, at most 2Read; also create with Read & write, within the plan's limit
Uptime monitors, SSL, domain and DNS checksAt most 3, public URLs, every 5 minutes or slowerRead; also add and change with Read & write
Deploy markersYesWith Read & write
Issues, events, logsReadRead
getSetupStatus, getWorkspaceYesYes
Alert channels, status pages, crawler, invites, browser errors, billingNo (403 not_until_claimed)No: a person turns these on in the dashboard
API tokens, teams, members, /meNo (403 agent_forbidden)No
Ingest10,000 events and 50 MB in totalThe Free plan's limits

A workspace token never gets more than this list, also after the claim. The agent can't create other tokens, invite people, publish a status page, send alerts to the outside world or pay. Those stay with people. Read-only is the default, because what an agent reads includes error messages and logs from your app, which could contain instructions meant for it.

Errors

Every error has code and message. These also have agent_hint, and where it helps retry_after (also as a Retry-After header).

StatuscodeWhat it means
400bad_requestPOST /workspaces: a name is missing or has characters that aren't allowed, or email isn't an address. createMonitor: the URL isn't public http(s), or interval_secs is under 300.
409conflictcreateMonitor: the workspace has its 3 monitors, or made 10 new monitors and URL changes today.
400pow_requiredNo pow in the request.
400pow_invalidThe challenge isn't ours, is easier than the server asks, or the nonce doesn't solve it.
400pow_expiredThe challenge is older than 10 minutes. Get a new one.
400pow_reusedThe challenge was used before. Get a new one.
404agent_signup_disabledAgents can't create workspaces right now. Ask your human to sign up and connect you with OAuth.
429rate_limitedToo many workspaces from this network: 3 unclaimed at a time and 10 a day. Wait retry_after seconds or ask your human to sign up.
503capacityNo room for new trial workspaces. Try again in an hour or ask your human to sign up.
403not_until_claimedNeeds a claimed workspace and a person: alert channels, status pages, billing, invites, browser keys, crawls.
403agent_forbiddenA workspace token can never do this (tokens, teams, members, /me, rotating an ingest token). A person does it in the dashboard.
403read_only_tokenAfter the claim the token is read-only until you confirm the code, and stays read-only if your human chose that. Also what createClaimLink answers then.
409already_claimedcreateClaimLink after the claim, with Read & write access: there is nothing to hand off.
400invalid_codeThe code is wrong. 5 tries in total.
410access_revokedThe code expired or was wrong 5 times. The token no longer works and the ingest tokens were replaced.
409not_pendingNo code is waiting: the workspace isn't claimed yet, or the code was confirmed already.
401workspace_expiredOn ingest and deploys: 72 hours passed without a claim. Create a new workspace; nothing carries over.
429workspace_fullOn ingest: 10,000 events or 50 MB used. Stop sending test data and hand off the claim link.
401workspace_deletedSomeone chose Not mine on the claim page.

Expiry

  • 6 hours: a workspace without any event is deleted as idle.
  • 72 hours: ingest stops (401 workspace_expired). The claim link still works.
  • 96 hours: the workspace is deleted with its projects, data, agent account and every token.

Claiming within that time makes the workspace a normal team on the Free plan. Nothing is deleted then.

Revoke the agent's access

  • Open Manage agent access from the "You claimed" email and click Disconnect agent.
  • Or remove the agent ("Claude Code (agent)") from the team's members.

Both remove every key of the agent and replace every ingest token of the team: update LAMPWICK_TOKEN in each app's .env. The same happens when the 30 days end, when the code isn't confirmed within 15 minutes and after 5 wrong codes.

Not mine

Got a claim link you didn't ask for? Open it, click Not mine, tick the box and click Delete workspace. That deletes the workspace and everything in it at once. You don't need an account for it. The agent's token then answers 401 workspace_deleted.

Bind the claim to an email

Send email with POST /workspaces and only an account with exactly that confirmed address can claim the workspace. A claim link that leaks into a transcript or a CI log is then useless to anyone else; the response says "claim_bound_to_email": true. Lampwick stores only a keyed hash of the address. It never shows it, never emails it and doesn't check whether an account exists for it. After the claim, claimed_by in getSetupStatus says "the bound address"; without a binding it says "someone else".

Without email, anyone with the link can claim the workspace. handoff_message says so.

Next step

Once the workspace is yours, set up alerts, then let the agent fix what breaks.