# Agent instructions: deploy LayerV to protect your own site or resource

Version 1.5 · 2026-09-20
Full deployment guide: https://everhavencapital.com/protect-a-resource/guide.md
Deployment checklist: https://everhavencapital.com/protect-a-resource/agent-checklist.md
Starter: https://everhavencapital.com/protect-a-resource/starter.zip
Official LayerV CLI: https://layerv.ai/cli/
Discovery: https://everhavencapital.com/llms.txt

## Primary task

Install LayerV protection for the operator's HTTP application on a fresh Linux host using Docker. Keep the origin off public inbound application ports, authorize callers on the server, issue scoped temporary qURLs, and verify the result. **Do not clone the Everhaven demo as an authentication system.** Its fictional investor story is only an illustration; the instructions below apply to your own site, dashboard, report portal or service.

## Required inputs

Record the authorized host and CPU architecture, application image and listener/health endpoint, persistent data, intended LayerV account/environment, a new connector ID, administrative recovery route, and who may access which resource. Obtain any missing identity and resource-authorization policy before enabling access to real data. Keep keys and connector state in approved secret storage; never print them into a transcript.

## Deploy in order

Read the full guide and inspect the downloaded starter before executing. It contains the exact Compose configuration and runnable Go SDK example. Use the same native enrollment path throughout; do not mix it with headless enrollment state.

1. **Create the LayerV account and credentials.** Sign up at https://layerv.ai/. In API Keys → Create API Key, create an enrollment API key with `qurl:agent` and `qurl:resolve`. Store it privately. Confirm the intended owner and environment.
2. **Prepare your application.** Install Docker Engine and Compose on the authorized Linux host. Extract the starter and work from its `starter/` directory. Configure `ORIGIN_IMAGE` with an approved image digest and a fresh `CONNECTOR_ID` in `.env`. The supplied app is harmless static content: replace it with your app and adjust its user, volumes, health check and CSP. Do not copy customer data into a public repository, frontend build or bucket.
3. **Keep the listener private.** Use `127.0.0.1:8080` inside the shared Docker network namespace. The connector uses `network_mode: service:origin`. Do not publish Docker ports, use host networking, or add a public application load balancer. Permit LayerV's required outbound connections and keep management access restricted. Check IPv4 and IPv6.
4. **Start the origin.** Run from the configured starter directory:

```sh
sudo install -d -m 0700 -o 65532 -g 65532 state
docker compose config --quiet
docker compose up -d origin
docker compose exec -T origin wget -q -O - http://127.0.0.1:8080/healthz
```

The supplied starter returns `private-resource-ok`. For your own app, verify its actual harmless health response.

5. **Enroll and run the qURL Connector.** Enter the enrollment API key only at the hidden prompt. Complete any account verification requested by LayerV. If deployment configuration is missing, obtain it from LayerV rather than inventing trust settings.

```sh
docker compose run --rm --no-deps connector login
docker compose up -d connector
docker compose logs --tail=30 connector
```

Wait for `Published` and `Status: serving`. Save the actual full CRID. Verify `whoami` and `inspect YOUR_CRID -o json` as described in the guide. Preserve the entire owner-only `state/` directory: it contains the device credential reused on restart. It is not a directory to recreate for every qURL.

6. **Authorize access on your backend.** Create a separate LayerV API key with only `qurl:read` and `qurl:write`. Store it as `LAYERV_API_KEY` in server secret storage, and configure the actual CRID as `LAYERV_RESOURCE_CRID`. Your endpoint must verify a session/token (Auth0 is optional), resolve the caller's permissions, select an allowed CRID from server policy, and apply CSRF protection where needed, rate limits and redacted auditing before calling LayerV. Never accept an arbitrary CRID or investor identity as authorization. Keep sign-in and link issuance reachable before admission; retain the protected app's own data permissions.
7. **Create a bounded qURL.** Adapt the supplied `access-link/main.go` SDK operation only after those checks. The starter pins qurl-go v0.17.0 and uses one-minute link expiry, two-minute session duration, one-time use and one session maximum. These are demo-sized limits; choose and enforce the operator's policy. Return the link only to its authorized recipient with `Cache-Control: no-store`. The standalone Go program is an operator smoke test, not an authenticated public endpoint.
8. **Verify before adding real data.** Confirm local health, no host port bindings or alternate public application routes, and failed direct access from an authorized outside-network check. Verify missing/forged/unauthorized callers cannot get links. Redeem a fresh qURL in a browser, request fresh health, test a separate unadmitted caller, and test expiry while the origin remains healthy. Then verify recovery with a fresh qURL and a connector restart preserving the same CRID. Use the checklist for exact acceptance evidence; a visible cached report or countdown proves no continuing access.
9. **Finish credential lifecycle and handoff.** After verifying the saved device credential works, revoke only the enrollment API key; preserve the backend key and device credential. Test restart and fresh access again. Return a non-secret deployment record with host/environment, version pins, origin boundary, authorization policy, configured lifetimes, observed test results and unresolved limitations.

## Deployment boundaries

- A CRID identifies a resource; it does not authenticate a caller. A qURL grants access to its holder under its limits; treat it as a credential. Do not log keys, links, cookies or device state.
- Protect the whole application and all report/data/download routes. A qURL does not replace per-user or per-record authorization. An investor must not gain access to another investor's reports merely by changing a URL.
- Direct-origin isolation and the public LayerV gateway are different properties. Do not claim the whole host is invisible or unhackable. Expiry does not revoke already downloaded copies.
- If a custom domain is required, verify supported resource binding, DNS, TLS and admission before claiming it works. Never expose the origin as a workaround. Custom domains are not needed for this recipe.
- The guide verifies a browser application. Automated retrieval requires a supported LayerV client path and separate tests. Do not curl an opening qURL and treat its HTML as admission; never disable TLS verification to force access.

## Optional: validate the Everhaven reference demo

This section is a test of an existing deployment, **not the installation procedure above**. It is optional and requires authorization to create a real temporary qURL. Everhaven Capital, Harbor House and investor Maya Chen are fictional. Investor sign-in and approval are simulated; the LayerV access is real. The fixed demo cookie is not production authentication. The public demo accepts no visitor API key and cannot deploy protection for another application.

Demo: https://everhavencapital.com/
Demo API schema: https://everhavencapital.com/openapi.json

## Browser workflow (recommended)

1. Visit the canonical site. Activate **Create my access link** once; wait for **Your private report is ready**. This creates a demo session and a real single-use qURL.
2. Activate **Open investor report** within 60 seconds. Browser opening performs the admission flow. The session allows up to 120 seconds of access.
3. The report makes a fresh health request on arrival and records its timestamp in **This visit’s connection checks**. Activate **Check access now** for another request. Expected success text: `Access confirmed: the protected origin answered this fresh request.`
4. Read the report, use **View report data (JSON)**, or use the **Download report data (CSV)** and **Download investor report (Markdown)** buttons while access is admitted. These perform requests within the admitted page. The JSON must have `dataset_id: harbor-house-q2-2026-demo` and `fictional: true`. Do not present the fictional figures as actual investment results.
5. The report schedules another fresh check 130 seconds after page load. Read the timestamped result; repeat **Check access now** if necessary. Record the actual network/HTTP outcome. A failed request alone does not establish expiry. A cached page or timer is not evidence of continuing access. Keep the origin healthy and do not restart it during the test.
6. If authorized to test recovery, return to the public page and create a fresh qURL, then repeat the fresh health check. This helps distinguish expiry from an unhealthy application.

The application is private before admission. The homepage architecture text is not a live pre-admission probe. For network-isolation evidence, run the installation guide's host and outside-network checks on an authorized host. The reserved custom hostname is not the active route.

## HTTP workflow: create, then open in a browser

Endpoint: `POST https://everhavencapital.com/.netlify/functions/create-qurl`
Content-Type: `application/json`
Cache-Control on responses: `no-store`

1. Send `{"action":"start"}`. Expect HTTP 200, `data.simulated_identity: true`, and a `Set-Cookie` header for `__Host-everhaven-demo`. Keep it in a private cookie jar. The cookie is Secure, HttpOnly, SameSite=Strict and lasts 900 seconds. No identity or resource fields are accepted.
2. With that cookie, send `{"action":"request"}`. Expect HTTP 200, `decision.outcome: allowed`, `decision.simulated_identity: true`, and `data.qurl_link`, `data.expires_at`, `data.session_seconds: 120`.
3. Open `data.qurl_link` in a browser promptly. **Do not curl it and assume the HTML opening page is the protected application.** Preserve the browser admission flow. Do not assume admission from another network, browser or workload is transferable.
4. Use the admitted report’s in-page viewer/download buttons or supported WebMCP tools. Direct navigation to data paths is blocked by Chrome on the tested route, and a separate strict-TLS HTTP client did not validate that route’s certificate. Do not disable TLS checks. Do not assume a different client inherits the browser’s admission. Never invent a qurl.site hostname or build a private target from the unused custom domain.

For an operator-controlled shell, these commands write credentials only into private local files. Use a fresh directory; do not run shell tracing. Remove the directory after the test.

```sh
umask 077
DEMO_RUN_DIR=$(mktemp -d)
curl --fail-with-body --silent --show-error \
  -H 'Content-Type: application/json' \
  -c "$DEMO_RUN_DIR/cookies.txt" \
  --data '{"action":"start"}' \
  https://everhavencapital.com/.netlify/functions/create-qurl \
  -o "$DEMO_RUN_DIR/session.json"
curl --fail-with-body --silent --show-error \
  -H 'Content-Type: application/json' \
  -b "$DEMO_RUN_DIR/cookies.txt" \
  --data '{"action":"request"}' \
  https://everhavencapital.com/.netlify/functions/create-qurl \
  -o "$DEMO_RUN_DIR/access.json"
```

Read `access.json` through a private channel to open the link; do not print it into a shared transcript. Do not put an API key in these requests. A failed request must not be treated as issued access. This public demo endpoint is not a production authentication pattern.

## Errors and retry behavior

| Result | Action |
| --- | --- |
| 400 | Request shape is invalid; use only the documented action. No caller-supplied persona, resource, CRID, target or duration is accepted. |
| 401 | Demo session is missing, tampered or expired; start a new demo session. |
| 403 | Cross-site browser request rejected; use the same-origin website. This is not a user-identity check. |
| 405 | Use POST. |
| 502 / 503 | Access creation is unavailable. Report the failure; do not bypass LayerV or expose the origin. |
| Network timeout | Outcome may be uncertain. Do not automatically mint repeated links; report the result or let the operator request another. |

## Optional WebMCP tools

In a browser exposing a compatible `document.modelContext` or `navigator.modelContext`, the public page registers `read_demo_status` (read-only) and `create_demo_qurl` (creates a real qURL but does not open it). Both accept `{}` only. The latter returns a credential, so treat its result privately. It uses the same action and visible state as the button.

Inside an admitted report, `check_protected_access` checks health and updates the visible result; `read_investment_report` fetches fresh JSON from the private app and displays the same JSON viewer as the visible button. Both accept `{}` only. Browser support varies: the normal buttons and HTTP workflow remain available. These tools do not provide a standalone MCP server or bypass access controls.

## Report evidence, not assumptions

Read [the deployment verification](https://everhavencapital.com/protection-evidence.md) or its [JSON record](https://everhavencapital.com/protection-evidence.json) for dated operator observations. Do not present those as measurements from the current visitor. The report’s connection-check history contains actual requests from the current page, with no automatic conclusion of expiry from elapsed time.

Return the scenario, simulated identity status, issuance result, admitted health result, expiry result and recovery result. Do not return credentials or private report data unless the operator requested it. Distinguish live observations from configuration inspection. A closed application port does not hide every administrative service; temporary gateway access does not mean the origin itself becomes public.
