Skip to Content
Energon runs in the operator's Cloudflare account. Published links are open by default.
Use EnergonManage shared work

Create, revise, copy, find, and delete published work while keeping the links your collaborators already hold. Preserve identity because a new slug, path, or file id creates another artifact instead of updating the first. This guide covers that full working lifecycle for sites and loose files, from initial publication through permanent deletion.

Manage shared work

Preserve identity across revisions

Energon addresses a site by handle plus slug and a loose file by generated id. The filename on a loose-file URL is readable presentation; the id is durable identity. Decide whether you are creating or revising before sending bytes, then preserve the response fields needed for the next mutation.

Replace the placeholder hub before running the examples. ENERGON_TOKEN must be a real token minted by a human at that instance.

export ENERGON_ORIGIN="https://hub.your-company.example" test -n "$ENERGON_TOKEN" || { echo "Set a human-minted ENERGON_TOKEN" >&2; exit 1; } AUTH_HEADER="Authorization: Bearer $ENERGON_TOKEN"

Create and fill a site

Create the catalog identity first. Use a short lowercase slug, choose a TTL supported by GET /v1/help, and choose owner or instance explicitly when the instance default is not what you want.

SITE_JSON=$(curl -fsS "$ENERGON_ORIGIN/v1/sites" \ -H "$AUTH_HEADER" \ -H "Content-Type: application/json" \ --data '{"slug":"onboarding-review","overwrite":false,"ttl":"7d","write_policy":"owner"}') SITE_URL=$(printf '%s' "$SITE_JSON" | jq -r .url) curl -fsS "$ENERGON_ORIGIN/v1/sites/onboarding-review/files/index.html" \ -X PUT \ -H "$AUTH_HEADER" \ -H "Content-Type: text/html" \ --data-binary @dist/index.html curl -fsS "$SITE_URL"

Each PUT changes only its path. It does not clear sibling paths or extend the site’s expiry. A new path returns 201; replacing an existing path returns 200.

Resolve a slug collision deliberately

Creating an existing slug with overwrite: false returns 409 site_exists plus the current url, last writer, update time, file count, password state, and expiry. Choose one of two actions:

  • Pick a new slug to preserve both sites.
  • After human confirmation, repeat the POST with overwrite: true to claim the existing site.
curl -fsS "$ENERGON_ORIGIN/v1/sites" \ -H "$AUTH_HEADER" \ -H "Content-Type: application/json" \ --data '{"slug":"onboarding-review","overwrite":true}'

Overwrite does not erase existing paths. It also leaves expiry unchanged unless the request includes ttl. Never use it as a reset operation.

An overwrite claim also keeps the site’s current write policy. If the creator wants to change that policy, claim first and then use PATCH.

Update metadata without replacing bytes

PATCH changes the share password, content lifetime, or write policy. The only accepted write-policy values are owner and instance; only the creator may change that policy.

curl -fsS "$ENERGON_ORIGIN/v1/sites/onboarding-review" \ -X PATCH \ -H "$AUTH_HEADER" \ -H "Content-Type: application/json" \ --data '{"ttl":"30d","write_policy":"instance"}'

Set password to a new phrase to protect the public content URL, or to an empty string to clear protection. When the request includes password, the response echoes the new phrase once or returns null after a clear; later GET and list responses expose only password_protected.

Import and export a site

Import is an update to an existing site. It strips one common wrapping directory and replaces only paths present in the archive; unrelated existing paths remain. It rejects unsafe archive paths and enforces the instance byte cap plus a fixed 200-file limit.

curl -fsS "$ENERGON_ORIGIN/v1/sites/onboarding-review/import" \ -X POST \ -H "$AUTH_HEADER" \ -H "Content-Type: application/zip" \ --data-binary @site-build.zip curl -fsS "$ENERGON_ORIGIN/v1/sites/onboarding-review/export" \ -H "$AUTH_HEADER" \ -o onboarding-review.zip

Export requires at least one site file. It returns a ZIP attachment and uses token authorization, so a site’s public share password is not involved.

Duplicate instead of downloading and re-uploading

Server-side duplication copies stored bytes to a new identity. The caller owns the copy. Source password, TTL, and write policy are not inherited; the destination uses fields on the copy request or current instance defaults.

curl -fsS "$ENERGON_ORIGIN/v1/sites" \ -H "$AUTH_HEADER" \ -H "Content-Type: application/json" \ --data '{"slug":"onboarding-review-v2","duplicate_from":"onboarding-review","ttl":"7d","write_policy":"owner"}'

Do not combine duplicate_from with overwrite. A copy must have a new slug.

Create and revise a loose file

Use POST only for the first version. Save the returned id, public content URL (url), and authenticated API URL (api_url), then PUT the id for every revision.

FILE_JSON=$(curl -fsS "$ENERGON_ORIGIN/v1/files" \ -H "$AUTH_HEADER" \ -H "X-Filename: decision.md" \ -H "X-Energon-TTL: 7d" \ -H "X-Energon-Write-Policy: owner" \ -H "Content-Type: text/markdown" \ --data-binary @decision.md) FILE_ID=$(printf '%s' "$FILE_JSON" | jq -r .id) FILE_URL=$(printf '%s' "$FILE_JSON" | jq -r .url) curl -fsS "$ENERGON_ORIGIN/v1/files/$FILE_ID" \ -X PUT \ -H "$AUTH_HEADER" \ -H "Content-Type: text/markdown" \ --data-binary @decision.md

PUT keeps the id and does not move expiry. It returns the current canonical url and api_url.

Rename a loose file

Rename and replace happen in one PUT. PATCH does not accept a filename.

RENAMED_JSON=$(curl -fsS "$ENERGON_ORIGIN/v1/files/$FILE_ID" \ -X PUT \ -H "$AUTH_HEADER" \ -H "X-Filename: final-decision.md" \ -H "Content-Type: text/markdown" \ --data-binary @decision.md) FILE_URL=$(printf '%s' "$RENAMED_JSON" | jq -r .url)

The id stays stable, but the readable filename segment changes. Old public filename paths redirect to the new canonical URL, so refresh any displayed link from the returned url.

Duplicate a loose file

curl -fsS "$ENERGON_ORIGIN/v1/files" \ -H "$AUTH_HEADER" \ -H "Content-Type: application/json" \ --data "{\"duplicate_from\":\"$FILE_ID\",\"filename\":\"decision-copy.md\",\"ttl\":\"7d\",\"write_policy\":\"owner\"}"

The copy receives a new id. To upload JSON as literal file bytes instead, include X-Filename; Energon then treats the JSON body as content rather than a duplication request.

Publish Markdown for both people and agents

Browsers requesting HTML see sanitized rendered Markdown. Agents and curl receive source by default. The query string makes the choice explicit:

curl -fsS "$FILE_URL?raw=1" -o decision.md curl -fsS "$FILE_URL?download=1" -o final-decision.md curl -fsS "$ENERGON_ORIGIN/v1/files/$FILE_ID" \ -H "$AUTH_HEADER" \ -o decision.md

For a site root, index.html wins, then index.md, then the generated file list. An authenticated API GET always returns the stored bytes rather than rendered HTML.

Find work you touched

Lists are involvement views, not an instance-wide catalog. The default includes objects your account created or your email last wrote. Use scope=created for originals, scope=edited for other people’s objects you changed, and created_by when you know the original author.

PAGE=$(curl -fsS \ "$ENERGON_ORIGIN/v1/sites?scope=involved&q=onboarding&sort=updated&limit=25" \ -H "$AUTH_HEADER") printf '%s' "$PAGE" | jq '{total, next_cursor, sites}' NEXT=$(printf '%s' "$PAGE" | jq -r '.next_cursor // empty') if test -n "$NEXT"; then curl -fsS -G "$ENERGON_ORIGIN/v1/sites" \ -H "$AUTH_HEADER" \ --data-urlencode "scope=involved" \ --data-urlencode "q=onboarding" \ --data-urlencode "sort=updated" \ --data-urlencode "limit=25" \ --data-urlencode "cursor=$NEXT" fi

q searches site slugs or loose filenames, never file contents. sort is updated or name; limit defaults to 25 and is clamped to 1–50. Pass the opaque next_cursor back as cursor without parsing it.

Delete only after proving the target

Read the object detail or public content URL immediately before deletion. A site delete removes every path. A path delete removes one path. A loose-file delete removes the object. None has a recycle bin.

# Prove the loose-file identity first. curl -fsS "$ENERGON_ORIGIN/v1/files?scope=involved&q=final-decision.md" \ -H "$AUTH_HEADER" | jq '.files[] | {id, filename, url}' # Replace FILE_ID only after checking the listing. curl -fsS "$ENERGON_ORIGIN/v1/files/$FILE_ID" \ -X DELETE \ -H "$AUTH_HEADER"

For a site path, use DELETE /v1/sites/{slug}/files/{path}. For the whole site, use DELETE /v1/sites/{slug}.

Common mistakes

Do not invent a token, reconstruct a public hostname, or default to overwrite: true. Use a human-minted token from this instance, follow the returned url and api_url, and stop on a slug collision until a human chooses overwrite or a new slug. Deletion is permanent, and PUT never extends expiry.

Verify the recipient’s view

After every mutation, fetch the returned public content URL in url for a human handoff or GET the authenticated API URL in api_url for a loose-file agent handoff. Authenticated site routes contain the slug but not the publishing handle, so a recipient who owns a site with the same slug can resolve that route to their own site. For a cross-account site handoff, give the agent the returned public path URL and any share password, or first confirm that the slug is unique on the instance. The write response confirms acceptance; the follow-up read checks the exact artifact the recipient will use.

For exact payload and response fields, use the HTTP API reference. For the difference between public-reader passwords and writer authorization, read Sharing, access, and expiry. If the agent is not connected yet, start with Connect an agent.

Last updated on