# Quickstart

> Create a Shardflux account and API key, then open a persistent workspace, run a command and check that a file survives suspend.

## What you will do

1. Sign up and create a project API key.
2. Open a workspace by key, run `python3 -c "print(40 + 2)"` in it and check the result.
3. Write a file, suspend the workspace, open the same key again and read the file back.

Pick one of the three paths: [TypeScript](#typescript-quick-start), [Python](#python-quick-start) or the
[CLI](#cli-quick-start). Each is a complete program or command sequence with the output to expect.

## Sign up and create an API key

1. Sign up at [https://app.shardflux.dev/signup](https://app.shardflux.dev/signup) and confirm your email address.
2. Create your organization (it starts on the Free plan) and your first project.
3. Open **API keys** in the console and choose **Create API key**. Give it a name, such as the service that will use
   it, and keep the workspace tools checked ("What code with this key can do in a workspace"). Opening and running
   workspaces needs at least one tool; organization owners and admins can create keys with tools.
4. Copy the key. It looks like `sfk_<key id>_<secret>` and is shown once. If you lose it, revoke it and create a new
   one.

Put it in your shell's environment. Every example on this site reads it from `SHARDFLUX_API_KEY`:

```sh
export SHARDFLUX_API_KEY=sfk_...
```

API keys are server credentials: keep them out of browsers and repositories.

### Or from a terminal

The `shard` CLI **(0.5.0+)** does the same steps without a browser, which is how a coding agent without an account
gets one. The password is read from standard input, never from an argument:

```sh
printf '%s\n' "$PASSWORD" | npx @shardflux/cli@latest auth register --email you@example.com
npx @shardflux/cli@latest auth verify-email '<link from the verification email>'
printf '%s\n' "$PASSWORD" | npx @shardflux/cli@latest auth login --email you@example.com
npx @shardflux/cli@latest setup
eval "$(npx @shardflux/cli@latest env)"
```

`auth verify-email` takes the link from the verification email (quoted), so a person opens that email or hands the
link over. `setup` creates the organization (on the Free plan), a project and an API key with every workspace tool,
and saves the key in `~/.config/shardflux/credentials.json`. `env` prints it as `export SHARDFLUX_API_KEY=...`, so
the `eval` line sets it for the examples below. See [Accounts and sign-in](https://docs.shardflux.dev/reference/cli.md#accounts-and-sign-in).

## TypeScript quick start

Needs Node.js 24 or later, which runs a `.ts` file directly.

```sh
mkdir shardflux-quickstart && cd shardflux-quickstart
npm init -y
npm pkg set type=module
npm install @shardflux/sdk
```

Save this as `quickstart.ts`:

```ts
import { Shardflux } from '@shardflux/sdk';

const cloud = new Shardflux({ apiKey: process.env.SHARDFLUX_API_KEY! });
const open = () => cloud.workspaces.open({ key: 'quickstart/demo', template: 'python-node-browser' });

// 1. Open the workspace (created on first use) and run a command. Check that it worked.
const workspace = await open();
console.log(`opened ${workspace.key}: ${workspace.state}`);
const run = await workspace.cell().exec.run(['python3', '-c', 'print(40 + 2)']);
if (run.exitCode !== 0) throw new Error(`python3 exited ${run.exitCode}: ${run.stderr}`);
console.log(`exit ${run.exitCode}, output ${run.stdout.trim()}`);

// 2. Write a file, then suspend the workspace and wait until the suspend has finished.
await workspace.cell().files.write('/home/user/notes.txt', 'hello from the SDK\n');
await workspace.suspend({ wait: true });
console.log(`after suspend: ${workspace.state}`);

// 3. Open the same key again: the workspace resumes, and the file is still there.
const again = await open();
console.log(`reopened: ${again.state}`);
console.log(`notes.txt: ${(await again.cell().files.readText('/home/user/notes.txt')).trim()}`);
```

Run it:

```sh
node quickstart.ts
```

Expected output:

```text
opened quickstart/demo: running
exit 0, output 42
after suspend: suspended
reopened: running
notes.txt: hello from the SDK
```

`open()` waits until the workspace is running. The first run creates the workspace, which takes longer than the
runs after it. `suspend({ wait: true })` resolves once the suspend has finished; without `wait` it resolves as soon
as the suspend is requested. See [Lifecycle](https://docs.shardflux.dev/concepts/lifecycle.md#requested-or-finished).

## Python quick start

Needs Python 3.10 or later.

```sh
mkdir shardflux-quickstart && cd shardflux-quickstart
python3 -m venv .venv && . .venv/bin/activate
pip install shardflux
```

Save this as `quickstart.py`:

```python
from shardflux import Shardflux

sf = Shardflux()  # reads SHARDFLUX_API_KEY


def open_workspace():
    return sf.open(key="quickstart/demo", template="python-node-browser")


# 1. Open the workspace (created on first use) and run a command. Check that it worked.
ws = open_workspace()
print(f"opened {ws.key}: {ws.state}")
result = ws.exec(["python3", "-c", "print(40 + 2)"])
if result.exit_code != 0:
    raise RuntimeError(f"python3 exited {result.exit_code}: {result.stderr}")
print(f"exit {result.exit_code}, output {result.stdout.strip()}")

# 2. Write a file, then suspend the workspace and wait until the suspend has finished.
ws.files.write("/home/user/notes.txt", "hello from Python\n")
ws.suspend(wait=True)
print(f"after suspend: {ws.state}")

# 3. Open the same key again: the workspace resumes, and the file is still there.
again = open_workspace()
print(f"reopened: {again.state}")
print(f"notes.txt: {again.files.read_text('/home/user/notes.txt').strip()}")
```

Run it:

```sh
python quickstart.py
```

Expected output:

```text
opened quickstart/demo: running
exit 0, output 42
after suspend: suspended
reopened: running
notes.txt: hello from Python
```

`ws.exec()` runs a list as argv without a shell; a string runs through `bash -lc`. `ws.suspend(wait=True)` returns
once the suspend has finished.

## CLI quick start

Needs Node.js 24 or later.

```sh
npm install -g @shardflux/cli
shard login
```

`shard login` checks the key and stores nothing. Expected output (your ids differ):

```text
Authenticated.
api           https://api.shardflux.dev
organization  <organization id>
project       <project id>
api key       <key id> (<api key id>)
tools         exec, files, pty, process, git, browser
The key comes from SHARDFLUX_API_KEY; shard stores nothing for it. To sign in to your account instead: shard auth login.
```

If you created the account [from a terminal](#or-from-a-terminal), `shard` also finds the key that `shard setup` saved
when `SHARDFLUX_API_KEY` is not set; the last line then says so.

Open a workspace, run a command, write a file and suspend:

```sh
shard ws open quickstart/cli --template python-node-browser
shard ws exec quickstart/cli -- python3 -c 'print(40 + 2)'
echo 'hello from the CLI' | shard files write quickstart/cli /home/user/notes.txt
shard ws suspend quickstart/cli --wait
```

Expected output (the workspace details after the first line are abbreviated):

```text
Workspace quickstart/cli (<workspace id>) is ready.
id           <workspace id>
key          quickstart/cli
state        running (desired running)
...
42
wrote 19 bytes to /home/user/notes.txt (sha256 <hash>)
Suspending quickstart/cli (<workspace id>): operation <operation id> suspend succeeded
```

`shard ws exec` exits with the command's own exit code. `ws` is short for `workspaces`, and `--` separates the
command from `shard`'s options. Without `--wait`, lifecycle commands return as soon as the operation is requested.

## Check that the workspace persisted

Read the file back. `shard files read` resumes the suspended workspace first:

```sh
shard files read quickstart/cli /home/user/notes.txt
shard ws get quickstart/cli
```

```text
hello from the CLI
id           <workspace id>
key          quickstart/cli
state        running (desired running)
...
```

The same works for the workspace the SDK programs used: `shard files read quickstart/demo /home/user/notes.txt`.
Running either program again prints the same lines, because opening a key never resets its workspace.

What these steps verified is the file. A suspend also keeps memory and running processes; see
[What survives each transition](https://docs.shardflux.dev/concepts/lifecycle.md#what-survives-each-transition).

## Clean up

A suspended workspace uses no compute, but its disk still counts toward your plan's retained storage. Delete the
workspaces when you are done. Deleting cannot be undone, and a deleted workspace's key is never reused:

```sh
shard ws delete quickstart/demo --yes
shard ws delete quickstart/cli --yes
```

## Next steps

- [Workspaces](https://docs.shardflux.dev/concepts/workspaces.md): keys, projects, API keys and tool tokens, sessions, sharing a workspace.
- [Lifecycle](https://docs.shardflux.dev/concepts/lifecycle.md): suspend, resume, fork and what survives each.
- [Give your agent workspace tools](https://docs.shardflux.dev/guides/agent-tools.md) with Anthropic, OpenAI and other model providers.
- [Use Shardflux with your coding agent](https://docs.shardflux.dev/guides/coding-agents.md).
