First Artifact

Create a complete HTML artifact, verify its durable revision, and choose a public or password-protected share.


This walkthrough creates a private static page, verifies that it is stored in a workspace revision, and then makes an explicit sharing choice. It uses the CLI so every step has a visible success signal.

Before you start

Complete Install. You need the desktop app, the managed grain command and a successful grain login. Use a new folder so the example does not upload unrelated files.

Copyable workflow

Create a page and publish it:

mkdir -p "$HOME/grain-first-artifact"
cd "$HOME/grain-first-artifact"
printf '%s\n' '<!doctype html><html><head><meta charset="utf-8"><title>First Grain artifact</title></head><body><h1>Hello from Grain</h1><p>This page is private until I choose to share it.</p></body></html>' > index.html

grain login
grain init --template html --name "First artifact" --no-open
grain push
grain checkpoint -m "first publish"
grain history --limit 1

The commands do the following:

  1. The first three shell lines create a complete index.html in a disposable local folder.
  2. grain login authenticates through the desktop app. It does not publish anything.
  3. grain init creates a static workspace, links the current folder and uploads managed content. --no-open keeps the app from opening automatically. It may write the project agent configuration described in Integrations.
  4. grain push synchronizes any changes still present in the checkout. Expected human output includes pushed <n> path(s); if init already uploaded the page, it may report that no additional change was needed.
  5. grain checkpoint records the authored tree as durable history. Expected output is checkpointed revision #<n> or checkout already matches the latest revision.
  6. grain history --limit 1 verifies that a revision exists. A history revision is the durable-save signal; a local file or open preview alone is not.

Because this walkthrough uses --no-open, init returns the workspace ID, revision metadata and agent-wiring results but does not open or print a private workspace URL. Keep the ID for explicit inspection, then ask the Grain app to open the private preview:

grain --workspace <workspace-id> status
grain --workspace <workspace-id> metadata
grain --workspace <workspace-id> open
grain --workspace <workspace-id> history --limit 5

grain open asks the running Grain app to open the selected workspace. The private preview is authenticated in the app; the command itself prints an app-handoff result rather than a public URL. If the app is not running, start it and retry. A history revision remains the durable-save signal, and no public share exists until you run the explicit share step below.

Make a delivery choice

Keep the artifact private while it is unfinished. When it is ready, choose one audience explicitly:

grain --workspace <workspace-id> share --public

Expected output includes a share URL such as https://<slug>.share.rungrain.com and a canonical workspace URL. Anyone with the public link can open it. For a password-protected link, keep the password out of the process argument list and shell history. The CLI accepts GRAIN_SHARE_PASSWORD through --password-env:

read -r -s GRAIN_SHARE_PASSWORD
printf '\n'
export GRAIN_SHARE_PASSWORD
grain --workspace <workspace-id> share --password-env
unset GRAIN_SHARE_PASSWORD

A password share requires both the link and the password. The hidden prompt reads the password without echoing it; unset removes it from the current shell afterward. --password '<password>' is also supported for disposable test values, but exposes the value to local process inspection and should not be used for a real secret. The current CLI/MCP creation surface is public or password; named-person/invite access may exist elsewhere in the product UI but is not a documented CLI flag. MCP share calls accept a password as a tool input and pass it to the CLI through this environment flow. See Data and privacy for revocation and copy behavior.

Inspect and manage existing shares without guessing a URL:

grain --json --workspace <workspace-id> share list
grain --json --workspace <workspace-id> share update <share-id> --mode off
grain --json --workspace <workspace-id> share revoke <share-id>

Edit and publish again

Edit index.html, then synchronize and checkpoint the same workspace:

grain --workspace <workspace-id> push
grain --workspace <workspace-id> checkpoint -m "update greeting"
grain --workspace <workspace-id> history --limit 2

Use the same workspace ID and checkout. Do not create a second workspace just because a push or checkpoint was uncertain.

Recover safely

  • Remote drift: If push says “The remote workspace changed since this folder was last synchronized”, run grain pull, inspect the preserved local changes, then push again. Do not use --force unless you have deliberately reviewed what it would replace.
  • Missing checkpoint message: add -m "..." ; the message is required for a new checkpoint.
  • Failed initialization: rerun with --keep-failed only when you need the partial workspace retained for inspection. If an uncertain request may have created a workspace, use grain list or the returned ID before retrying.
  • Wrong audience: run share list, select the returned share ID and use share update --mode off or share revoke. Revocation prevents future access but cannot retract copies already downloaded.
  • Runtime command on HTML: this template has no compute sandbox. Use App Runtime and promote to a runtime template if the artifact needs code execution.