For AI agents: the complete documentation index is available at /llms.txt, the full documentation bundle is available at /llms-full.txt, and this page is available as Markdown at /automations/overview.md.

Automations

Info

Takeaways:

  • A loop runs one action each time one of its triggers starts it. Each start is a run.
  • A trigger is an event (a labeled GitHub issue, a pull request review, a delegated Linear issue), a schedule, or a person starting the action by hand.
  • A factory is the set of loops working on one repository, for example turning tickets into pull requests and answering reviews on them.
  • A loop is either set up in Tessl (app-defined) or declared in tessl.json (repo-defined).
  • Tessl runs loops in its cloud. You need CI only when the work has to run inside your own pipeline.

You answer the same review comments, triage the same issues, and run the same weekly checks. Automations hand that recurring work to an agent, started by the thing that already tells you it needs doing.

How the pieces fit

One vocabulary runs through the web app, the CLI, and tessl.json:

  • Factory: the loops working on one repository. A factory can be one loop, such as a weekly docs audit. It can also be several loops that hand work to each other: one implements a ticket, and another answers reviews on the pull request it opens. Start with one loop and add more as each one earns its place.
  • Loop: one action and the triggers that start it. Loops are listed on the project's Loops tab in the web app and by tessl schedule list.
  • Action: what a run does. It names the skill to run and, optionally, the environment, agent, model, inputs, and instructions.
  • Trigger: what starts the action. A loop can have several:
    • an event trigger fires when a GitHub, Linear, Slack, or Tessl event matches its conditions;
    • a schedule fires on a cron;
    • a manual run starts the action on request, with Trigger now in the web app or tessl action trigger <name>. A loop whose triggers are all events has no button in the web app, because a manual run has no event.
  • Run: one execution of the action in Tessl's cloud. Each run has a status, a result, and a transcript you can read from the loop's page or with tessl launch view.

So the path is factory, then loop, then action, then trigger, then run. A labeled GitHub issue (trigger) starts the implement action (action) of the "ship tickets" loop (loop), which creates one run, and the factory is that loop plus any others on the repository.

App-defined and repo-defined loops

You can create a loop in two places. Both run the same way.

  • App-defined: set up in the web app, by the factory-setup skill, or with the CLI. Ticket to PR and Learn from past work are set up this way. You change them in Tessl, and they show no tessl.json entry. Ticket to PR's four loops (Implement ticket, Shepherd PR, Follow ticket changes, and Merge conflict sweep) have no Edit button in the web app. To change their instructions, model, environment, or who can start them, ask your coding agent with the tessl-labs/factory-setup plugin installed to move them into tessl.json. It moves all of the project's loops set up in Tessl together, in one pull request. This agent route is US only for now: the plugin isn't published on the EU region yet. Code Review isn't a loop: it's a repository setting you turn off and on for each repository.
  • Repo-defined: declared in the actions, triggers, and schedules blocks of tessl.json and synced when you push to the default branch. The loop is reviewed and versioned with the code it runs against. A repo-defined loop's page shows "Defined in tessl.json". When repo-defined loops are enabled for your organization, the web app and CLI won't edit one: change the file and push.

An app-defined loop that has an Edit button on its page can also move on its own: choose Edit on its page, then Open pull request, and Tessl opens a pull request that adds the loop to the file. Its runs and findings stay on the loop's page.

To pause, remove, or move a loop of either kind, and to cancel a run already in progress, see Stop, remove, and move loops.

Declare a loop in tessl.json

A repo-defined loop is an action and the entries that name it. This example declares one action and starts it two ways: when someone adds the tessl label to an open issue, and every Monday morning.

{
  "name": "engteam/my-repo",
  "actions": {
    "triage": {
      "skill": "engteam/issue-triage",
      "environment": "production"
    }
  },
  "triggers": {
    "issue-labeled": {
      "on": ["github:issues.labeled"],
      "when": {
        "event.label.name": "tessl",
        "event.issue.state": "open"
      },
      "action": {
        "use": "triage",
        "inputs": { "GITHUB_ISSUE_NUMBER": "{{ event.issue.number }}" }
      }
    }
  },
  "schedules": {
    "triage-weekly": {
      "action": "triage",
      "schedule": "weekly on monday at 08:00"
    }
  }
}

Both entries name the declared action, so they are one loop, named after the action. tessl action trigger triage starts the same action by hand. The field-by-field reference is in Configuration files, and the schedules block is described in full in Schedules.

Check the file before you push:

tessl doctor --automations

It validates the actions, triggers, and schedules blocks together. tessl schedule validate checks the schedules block and the actions it names.

Event triggers

An event trigger names the events it listens for in on, as <provider>:<event>, and narrows them with conditions in when. A condition key is a path into the event's payload, written event.…. Values pass to the action through inputs with {{ event.… }} substitutions.

GitHub events come through the Tessl GitHub App, so the app must have access to the repository. See Connect Tessl to GitHub. Common GitHub events:

  • github:issues.labeled and github:issues.opened: work on an issue.
  • github:issue_comment.created: a comment on an issue or pull request.
  • github:pull_request_review.submitted and github:pull_request_review_comment.created: answer a review.
  • github:check_run.completed and github:check_suite.completed: react to CI results.

A trigger listens for one event shape, the part of the event name before the first dot. github:issues.opened and github:issues.labeled can share a trigger; github:issues.labeled and github:issue_comment.created can't.

This trigger runs a declared respond action when a review is submitted on an open pull request from a tessl/ branch:

{
  "triggers": {
    "pr-review": {
      "on": ["github:pull_request_review.submitted"],
      "when": {
        "event.pull_request.head.ref": { "matches": "^tessl/" },
        "event.pull_request.state": "open"
      },
      "action": {
        "use": "respond",
        "inputs": { "GITHUB_PR_NUMBER": "{{ event.pull_request.number }}" }
      }
    }
  }
}

Linear events, such as linear:Issue.create and linear:Issue.update, need two things first: Linear connected to the workspace, and a Linear team routed to the project. A run that reads or writes Linear also needs an environment with Linear access. See Least privilege for environments. The Linear connection isn't offered on the EU region.

Hosted loops or CI

Tessl runs every loop in its cloud. There's no workflow file to maintain and no runner to provision, and the loop's runs are listed in one place.

Use CI instead when the work must run inside your pipeline: a check that gates a pull request, a job that needs your build cache or private network, or a step in an existing release workflow. tessl launch skill runs a skill headlessly from any CI job. Automating repetitive tasks walks through both choices.

Next steps

Example schedules

Example Schedules