Set up, understand, and change a Tessl factory on a repository: pick automations that fit how you work, such as shipping tickets as pull requests, answering reviews and fixing checks on those pull requests, code review, and scheduled jobs; prepare the repository for agents; write issues for the factory to build; then see what the factory has done, find out why a run failed or never started, and change or extend it.
92%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
What to put in a skill that a factory automation runs. Read this before drafting or editing one.
A factory skill runs as a one-shot round: a fresh agent with no memory of
earlier rounds, on the agent and model its automation names. Tessl's cloud
prepares the run before the agent starts: the clone, GitHub authentication,
.cloud-launch/trigger-events.json with the events that started the round, the
installed skill, the inputs in .cloud-launch/inputs.json, the team's rules
in .cloud-launch/instructions.md, and the repository's setup hook. What it
does not provide is anything between rounds. An agent harness, code that runs
an agent round after round, can skip feedback it has handled, retry a failed
round and stand down when the ticket is stopped; a factory automation has only
its skill text, its triggers or schedule, and the scripts and tools the skill
ships with, so what those do not say or enforce does not happen. A numbered
procedure copied from a prompt written for a harness becomes choreography the
agent misreads (Taking over from what runs today says
how to learn from such a prompt without copying it), and two paragraphs that
disagree get applied to the wrong case. Say in the skill which wins when the
team's rules in instructions.md conflict with its invariants.
The starting state is unknown to every factory skill, including one that runs once from start to finish. A run-once skill can be launched against an issue a person has half-done, run again after a round that pushed a branch and crashed before opening the pull request, or woken again by an edit to an issue that is still waiting to start. A numbered procedure assumes one starting state and one path from it. Every other start has to be added as an early exit, each exit can only stop, and for a start nobody listed the agent runs the steps from the top or guesses where to resume. A finished state with the situations that can precede it, each with its next action, gives the agent something to match against whatever the pull request, the issue or other record shows.
Write the skill in four parts, never as a numbered list of steps to perform in order. A numbered list of situations in precedence order is fine:
The skill does not describe its own configuration: no prose about how its triggers or concurrency are set up, no step that checks that setup, no note that an invariant is also enforced elsewhere, no history of what it replaced. What wakes the agent, and what does not, is an environment fact and belongs in the skill ("nothing wakes you when the base branch moves; if the pull request needs something no event will bring, say so on it"). The design gap behind it belongs in your own notes or issue tracker, not in the skill.
Ticket state is output, not input. Have the agent write the ticket's state to mirror the work, for the people reading the board, and read it only for what a person sets to steer the work: the state that starts it, the state or delegate change that takes it back, and the states that end it. Have it judge those from the record as well as the state: what the person said last, and what the agent itself said before it.
A skill's inputs are declared in its schemas/inputs.schema.json, which its
SKILL.md frontmatter links. The automation that launches the skill fills
them: each trigger maps the event onto them, and a schedule passes fixed
values. They set inputs by name, so renaming an input breaks every trigger and
Loop that sets the old name, and making one required breaks every one that
does not set it; for a published skill, those are in other repositories.
LINEAR_ISSUE_IDENTIFIER or GITHUB_PR_NUMBER, and every
trigger that starts it maps that input. A missing required input then fails
the launch before any agent runs. It never falls back to
.cloud-launch/trigger-events.json to find that subject. It may read the
events for facts only they carry (a skill that runs when a pull request
closes reads the merge result and head branch), and it stops without a write
when they name a different subject. A skill whose run folds several events
into one, such as one that posts a summary of new findings, reads its
subjects from the events, and a scheduled skill finds its own set of things
to work on; this point covers neither.GITHUB_, LINEAR_ or SLACK_, when its value belongs to
that system. Git values
(BRANCH, BASE_BRANCH) and run settings (DRY_RUN) have no prefix.