Get started with doneyet

Connect your first job in a few minutes — sign in, grab a token, wrap a run with start → heartbeat → finish. Use the dyt CLI or call the REST API directly.

The model

doneyet watches background work through a tiny contract your job calls around itself:

  • start — register a run when the job begins. doneyet now expects it to finish within its grace + SLA window.
  • heartbeat — ping while it works (every few seconds for long jobs). Go quiet past the grace window → a stall alert fires.
  • finish — report succeeded or failed. No finish + no heartbeat → doneyet pages on-call.

A workflow is the named, recurring job (e.g. nightly-export); a run is one execution of it. Everything lives in a workspace (your org's boundary).

1Sign in & create a workspace

Open app.doneyet.io, sign in, and create a workspace. The free tier needs no card.

[ screenshot: workspace creation ]
Creating a workspace in the dashboard.

2Get an access token (PAT)

Programmatic access uses a Personal Access Token scoped to your workspace. Mint one from the dashboard under Admin → Access tokens, or with the CLI once you've signed in there:

# from the dashboard: Admin → Access tokens → New token
# or, with an existing admin token, mint a scoped service token:
dyt pat create --label ci-runner --ttl-days 90 --show
Treat it like a password. A PAT is workspace-scoped and carries write access. Store it in your CI secret store, not in source. PATs require an expiry (max 5 years); rotate with dyt pat revoke <id> + a fresh create.
[ screenshot: Access tokens page ]
Minting a PAT from Admin → Access tokens.

3Install the dyt CLI

Pre-built static binaries are on GitHub Releases — pick your platform:

# Linux amd64
curl -fsSL -o dyt https://github.com/lucheeseng827/doneyet-cli/releases/latest/download/dyt-linux-amd64
chmod +x dyt && sudo mv dyt /usr/local/bin/

# macOS arm64
curl -fsSL -o dyt https://github.com/lucheeseng827/doneyet-cli/releases/latest/download/dyt-darwin-arm64
chmod +x dyt && sudo mv dyt /usr/local/bin/

dyt --version

linux/arm64 and windows/amd64 builds are on the same release page. No installer? You can also call the REST API directly — see REST API.

4Point dyt at your workspace

dyt config set api-url https://app.doneyet.io
dyt login --admin-token -        # paste your PAT at the hidden prompt
dyt health                       # → ok
dyt whoami                       # resolved config + server ping

Prefer env vars (CI)? Skip login and export instead:

export DONEYET_API_URL=https://app.doneyet.io
export DONEYET_ADMIN_TOKEN=<your-PAT>

5Register a workflow

Tell doneyet about the job once. heartbeat-grace-s is how long it may go silent before a stall fires; expected-duration-s drives overrun detection.

dyt workflow upsert \
  --slug nightly-export \
  --name "Nightly Export" \
  --owner group:default/data \
  --heartbeat-grace-s 120 \
  --expected-duration-s 600

dyt workflow list                # confirm it's there

6Wrap a run: start → heartbeat → finish

run start returns an id and a one-time run token used for heartbeat/finish on that run:

# start; capture the run id + run token
START=$(dyt run start nightly-export --output json)
RUN=$(echo "$START" | jq -r .id)
export DONEYET_RUN_TOKEN=$(echo "$START" | jq -r .token)

# … do the work, heartbeating along the way …
dyt run heartbeat "$RUN" --progress 50 --message "halfway"
dyt run heartbeat "$RUN" --progress 90

# report the outcome
dyt run finish "$RUN" --status succeeded

For a long job you don't want to instrument internally, let dyt heartbeat for you while the work runs:

START=$(dyt run start nightly-export --output json)
RUN=$(echo "$START" | jq -r .id); export DONEYET_RUN_TOKEN=$(echo "$START" | jq -r .token)

dyt run tail "$RUN" --interval 15 &   # background auto-heartbeat
HB=$!
./your-actual-job.sh                  # the real work
kill $HB
dyt run finish "$RUN" --status $([ $? -eq 0 ] && echo succeeded || echo failed)

CI / cron examples

GitHub Actions

- name: Run nightly export (tracked by doneyet)
  env:
    DONEYET_API_URL: https://app.doneyet.io
    DONEYET_ADMIN_TOKEN: ${{ secrets.DONEYET_TOKEN }}
  run: |
    START=$(dyt run start nightly-export --external-ref "$GITHUB_RUN_ID" --output json)
    RUN=$(echo "$START" | jq -r .id); export DONEYET_RUN_TOKEN=$(echo "$START" | jq -r .token)
    if make nightly-export; then dyt run finish "$RUN" --status succeeded;
    else dyt run finish "$RUN" --status failed; exit 1; fi

Cron wrapper

# /etc/cron.d/nightly — wrap any command
0 2 * * *  app  DONEYET_API_URL=https://app.doneyet.io DONEYET_ADMIN_TOKEN=… \
  bash -c 'S=$(dyt run start nightly-export -o json); R=$(jq -r .id <<<"$S"); \
           export DONEYET_RUN_TOKEN=$(jq -r .token <<<"$S"); \
           /opt/jobs/export.sh && dyt run finish "$R" --status succeeded || dyt run finish "$R" --status failed'

7Get alerted

Add a channel so stalls/failures reach you. Slack, PagerDuty, Opsgenie, email, or a signed webhook:

dyt notify channel create \
  --kind slack \
  --name oncall \
  --target https://hooks.slack.com/services/T000/B000/xxxx

Then route events to it with a notification rule (dashboard Admin → Notifications, or POST /api/v1/notification-rules). Test it: start a run and send no heartbeats for heartbeat-grace-s + 30s — you should get exactly one alert.

[ screenshot: alert in Slack + the dashboard inbox ]
A stall alert delivered to Slack, with the run in the dashboard inbox.

Talk to the REST API directly

No CLI needed — the same flow over HTTPS. Workspace-scoped PAT as a bearer; the run endpoints use the run token returned by start.

StepCallAuth
Register workflowPOST /api/v1/workflowsPAT
Start runPOST /api/v1/workflows/{slug}/runsPAT
HeartbeatPOST /api/v1/runs/{id}/heartbeatrun token
FinishPOST /api/v1/runs/{id}/finishrun token
List runs / overviewGET /api/v1/runs · /overviewPAT
BASE=https://app.doneyet.io/api/v1
PAT=<your-PAT>

# 1. register the workflow
curl -fsS -X POST "$BASE/workflows" -H "Authorization: Bearer $PAT" \
  -H 'Content-Type: application/json' \
  -d '{"slug":"nightly-export","name":"Nightly Export","heartbeat_grace_s":120}'

# 2. start a run → returns {"id":"...","token":"..."}
RESP=$(curl -fsS -X POST "$BASE/workflows/nightly-export/runs" \
  -H "Authorization: Bearer $PAT" -H 'Content-Type: application/json' -d '{}')
RUN=$(jq -r .id <<<"$RESP"); RTOK=$(jq -r .token <<<"$RESP")

# 3. heartbeat (run token)
curl -fsS -X POST "$BASE/runs/$RUN/heartbeat" \
  -H "Authorization: Bearer $RTOK" -H 'Content-Type: application/json' \
  -d '{"progress":50,"message":"halfway"}'

# 4. finish
curl -fsS -X POST "$BASE/runs/$RUN/finish" \
  -H "Authorization: Bearer $RTOK" -H 'Content-Type: application/json' \
  -d '{"status":"succeeded"}'
A workspace-bound PAT already carries its workspace, so no extra header is needed. (Dashboard/SSO sessions select a workspace via the X-Doneyet-Workspace header.)

Next steps

  • See it live: open the dashboard — your runs, statuses, durations, and alert inbox.
  • SLA windows: set --expected-duration-s so a "successful" job that ran 3× too long still gets flagged.
  • Producers: shell wrapper, k8s sidecar, GitHub Actions step — open-source under Apache 2.0.
  • Help: stuck? email support@doneyet.io.