clay

Quick Rundown

Intro to clay

Everything you need to go from an empty terminal to a workflow you drive from your phone. Install it, edit some JSON, point it at a model, decide what it is allowed to touch, and summon it from anywhere.

Page I

The first incantation

One line installs Clay with its own Python 3.11 and an offline wheelhouse. It does not touch your system Python, and it does not need one.

terminalmacOS & Linux
$ curl -fsSL https://claycli.org/install.sh | sh
$ export PATH="$HOME/.local/bin:$PATH"
$ clay --version

Clay lands in ~/.local/share/clay with its launcher at ~/.local/bin/clay. Add the Qt desktop app by passing -s -- --ui to the same installer.

See what came with it

Clay ships a library of workflows. List them, then run one by its segments.

terminalfind and run
$ clay workflows              # everything installed
$ clay workflows coding       # filter by name
$ clay workflows --paths      # show the files behind them

$ clay run templates content quick-explainer
$ clay run -f ./my-workflow.json
Where it runs The directory you are standing in becomes the workflow's project directory — the place its file actions operate, after you approve it. Aim somewhere else with clay --project-dir /path/to/project run …

Page II

The shape of a workflow

A workflow is made up of JSON files. workflow.steps lists the steps in order. actionSets holds the actions inside each step. That is the whole language.

draft.jsonask → draft → save
{
  "workflow": {
    "steps": ["ask", "draft", "save"]
  },
  "actionSets": {
    "ask": [
      {
        "id": "topic",
        "type": "humanDecision",
        "prompt": "What should I write about?"
      }
    ],
    "draft": [
      {
        "id": "article",
        "type": "scramda2",
        "prompt": "Write three paragraphs about {topic}.",
        "includedData": ["topic"]
      }
    ],
    "save": [
      {
        "id": "saved",
        "type": "writeFile",
        "file": "draft.md",
        "content": "article"
      }
    ]
  }
}
  • id names the output."id": "topic" stores that action's result under the name topic, for anything later to use.
  • includedData asks for it back. List the names this action needs and they arrive as data.
  • {name} drops a value into text.{topic} becomes whatever the person typed, before the prompt ever reaches the model.
  • when and whenNot gate an action. Point one at an earlier output and the action runs only if that answer means yes — or no. false, done, 0, no, stop and empty mean no; anything else means yes. So a model answering YES branches your workflow directly.

Agents are loops you wrote

The loop action runs a sub-workflow over and over. continueKey names the output that tells it to stop. A loop, a gate, and outputs you named yourself — that is the entire harness. The model fills in text and answers questions. Your JSON decides what happens next.

agent.jsonrun until it says done
{
  "id": "session",
  "type": "loop",
  "file": "iteration.json",
  "iterations": 12,
  "continueKey": "keep_going"
}

Check it before you run it

terminalvalidate
$ clay lint ./draft.json      # unknown fields, bad references
$ clay dryrun ./draft.json    # walk it without executing
$ clay create my-workflow     # build one interactively

Page III

Binding a model

Every AI step posts to an OpenAI-compatible server. By default that is a server on your own machine, which means your prompts and your files never leave it.

terminaldefault endpoint
# the default, if you set nothing at all
$ export GOPHER_URL=http://127.0.0.1:8080

Point it anywhere you can reach — another machine on your network, or a hosted endpoint if you decide you want one. That decision is yours, and it is one environment variable.

Name your models once

Model profiles live in ~/.clay/config.json. Give each one a name, and any action can ask for it by name instead of hard-coding a model into twenty different workflow files.

workflow actionpick a profile
{
  "id": "plan",
  "type": "scramda2",
  "modelProfile": "code",
  "prompt": "Write an implementation plan for {goal}",
  "includedData": ["goal"]
}
No middleman There is no account, no telemetry, and no vendor service between you and your model. Clay talks to the endpoint you name, and nothing else.

Page IV

Gates and wards

Workflow files are programs. They can write files, read files, and run commands. Clay gates all three separately, and every gate names exactly what it is about to do before it does it.

  • writes — asked before anything reaches disk.
  • reads — asked before anything is opened.
  • commands — asked before anything is executed.

Switch them from any prompt, mid-run. One grammar, and it works the same in the terminal, in the desktop app, and in a Telegram chat.

any promptmanual mode
/manual                # show current settings
/manual on             # master switch, everything asks
/manual writes off     # one gate at a time
/manual reads on
/manual commands on

Directories are approved, not assumed

File actions only reach directories you have approved. Approve them ahead of time, or answer the prompt when a run asks — once, always, or not at all.

terminalapproved directories
$ clay dirs list
$ clay dirs add /path/to/project
$ clay dirs forget /path/to/project
Read before you run A workflow from someone else is code from someone else. Read it first, especially before running it unattended or under the daemon.

Page V

The far summoning

Clay can run a Telegram bot as your remote control. You get a menu of your workflows in a chat. Tap one and it starts. When it needs an answer, the question arrives as a message — you reply, and your reply goes back in as the answer.

The bot is a front-end, exactly like the desktop app. It never runs a workflow itself; it asks the clayd daemon to run it. The work happens on your machine whether or not your phone stays awake, and one workflow runs at a time per bot.

terminalstart the channel
$ export TELEGRAM_BOT_TOKEN='123456:token-from-BotFather'
$ export TELEGRAM_ALLOWED_USERS='123456789'
$ clay run system messaging telegram
Fails closed The bot will not start without a token and at least one numeric user or chat allowlist. There is no open mode, and messages from anyone not on the list are ignored.

Choose what appears in the menu

The buttons come from the action itself, so the bot only ever offers the workflows you listed.

telegram actionyour menu
{
  "id": "bot",
  "type": "telegram",
  "workflows": [
    {"label": "Coding",   "path": "workflows/system/coding4/main.json"},
    {"label": "Research", "path": "workflows/templates/research/main.json"}
  ]
}

Your gates come with you. Send /manual from the chat to switch them, and approve writes, reads, and commands from your phone before they happen — the same grammar as page IV.

Or leave it running headless

The daemon keeps workflows alive across terminals, reboots, and disconnects. Attach whenever you want to look.

terminalclayd
$ clay daemon start
$ clay daemon run templates research main
$ clay daemon list
$ clay daemon tail wf-0001
$ clay daemon attach wf-0001

That is the whole engine

Simple JSON structure, a model you chose, gates you set, and a chat window if you want one. The rest is just workflows — and you can read every one of them before it runs.